From 4bab9c361a8205359587baf4dbb7320b4da38dd1 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 7 Sep 2026 15:31:43 +0100 Subject: [PATCH 01/11] jenkins/systemd-run-wrap.sh: Greatly simplify this script As far as I can tell, practically all the workarounds in this script are no longer required. A scope unit (as opposed to a service unit) seems to do everything we want. Scope units automatically inherit the environment, avoiding the need to explicitly pass potentially sensitive values on the command line. Despite the 5 year old comment about using a system unit because a user unit may not work in CI, I have found that a user unit works just fine. Conversely, a system scope unit created with sudo breaks access to the Docker socket because it does not set up the supplementary groups. Signed-off-by: James Le Cuirot --- jenkins/systemd-run-wrap.sh | 38 +++++++------------------------------ 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/jenkins/systemd-run-wrap.sh b/jenkins/systemd-run-wrap.sh index 4b5c4e0b974..315b8f3b9e1 100755 --- a/jenkins/systemd-run-wrap.sh +++ b/jenkins/systemd-run-wrap.sh @@ -1,34 +1,10 @@ #!/bin/bash set -euo pipefail -# note: to make sure you forward the whole env, you can first run 'source <(export)' before starting this script -# Add /opt/bin explicitly because the lbzcat binary is there on the Jenkins workers -export PATH="$PATH:/opt/bin" - -# Use a system session unit because the user session may not be set up correctly in a CI env -ARGS=("--system" "--collect" "--same-dir" "--pipe" "--wait" "--property=User=$USER" "--property=Group=$USER") -# Extra "bash -c" is needed to only export the exported variables. Do -# not use sh - it will add POSIXLY_CORRECT into the environment, which -# is unnecessary. -for VARNAME in $(bash -c 'compgen -v'); do - set +u - VAL="${!VARNAME}" - set -u - ARGS+=("--setenv" "${VARNAME}=${VAL}") -done - -UNITNAME="run-$(date '+%s')-${RANDOM}" - -# The --pipe option does not stop the unit when the systemd-run process is killed, we have to do this through a trap -# (and --pty as alternative doesn't behave well because it leads to processes expecting stdin when there is none) -function cancel() { - echo - echo "Terminating" - sudo systemctl stop "${UNITNAME}" - exit 1 -} -trap cancel INT - -ARGS+=("--unit=${UNITNAME}") - -sudo systemd-run "${ARGS[@]}" "$@" +exec systemd-run \ + --user \ + --scope \ + --collect \ + --same-dir \ + --expand-environment=no \ + "${@}" From 384256d1002643aac492671374ff4382b9774047 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 2 Oct 2026 17:38:38 +0100 Subject: [PATCH 02/11] sdk_entry.sh: Greatly simplify switching to the sdk user We want environment variables passed through Docker with --env and --env-file to survive the sudo call, but -E cannot be combined with -i. However, we can still effectively get a login shell by calling bash -l. I considered runuser, which doesn't have the stdout/stderr issue we faced earlier, but that has the same limitation as sudo. I also considered setpriv, but that is quite low-level, requiring you to manually fix up variables like HOME. What the comment said about Docker's --user option only applying a single group doesn't appear to be true (anymore?), so we could probably start the container as the sdk user and do the initial privileged tasks with sudo, but that's a bigger change for later. While doing this, I realised that the passing commands through can be done much more simply by passing them as additional arguments to bash. Signed-off-by: James Le Cuirot --- sdk_lib/sdk_entry.sh | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/sdk_lib/sdk_entry.sh b/sdk_lib/sdk_entry.sh index 8757b4b39b9..887015e2f48 100755 --- a/sdk_lib/sdk_entry.sh +++ b/sdk_lib/sdk_entry.sh @@ -54,9 +54,8 @@ sed -i -r '/^masters =/s/\bcoreos(\s|$)/coreos-overlay\1/g' /usr/local/portage/c fi ) -# SDK container is launched using the su command below, which does not preserve environment -# moreover, if multiple shells are attached to the same container, -# we want all of them to share the same value of the variable, therefore we need to save it in .bashrc +# If multiple shells are attached to the same container, we want all of them to +# share the same value of the variable, therefore we need to save it in .bashrc. # Check if MODULE_SIGNING_KEY_DIR exists in .bashrc and if the directory actually exists if grep -q 'export MODULE_SIGNING_KEY_DIR=' /home/sdk/.bashrc; then # Extract the existing path @@ -132,29 +131,8 @@ grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { popd > /dev/null } -# This is ugly. -# We need to sudo -u sdk -i so the SDK user gets a fresh login. -# 'sdk' is member of multiple groups, and plain docker USER only -# allows specifying membership of a single group. -# When a command is passed to the container, we run, respectively: -# sudo -u sdk "". -# Then, we need to preserve whitespaces in arguments of commands -# passed to the container, e.g. -# ./update_chroot --toolchain_boards="amd64-usr arm64-usr". -# This is done via a separate ".cmd" file since we have used up -# our quotes for sudo "" already. -if [ $# -gt 0 ] ; then - cmd="/home/sdk/.cmd" - echo -n "exec bash -l -i -c '" >"$cmd" - for arg in "$@"; do - echo -n "\"$arg\" " >>"$cmd" - done - echo "'" >>"$cmd" - chmod 755 "$cmd" - sudo -u sdk "$cmd" - rc=$? - rm -f "$cmd" - exit $rc -else - exec sudo -u sdk -i -fi +# We need to sudo -u sdk with bash -l so that the SDK user gets a fresh login. +# sudo has an -i option to get a login shell, but that cannot be combined with +# -E to preserve the environment. We already have a relatively clean environment +# inside the container, but we want to preserve variables passed through Docker. +exec sudo -u sdk -EH bash -l -i ${1+-c '"${@}"' -- "${@}"} From aa70a2df9d32ad6ba44e5d2a5fcadef763f3aca5 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 2 Oct 2026 18:25:51 +0100 Subject: [PATCH 03/11] Switch from shadow's su to util-linux's and drop su from the SDK shadow's su is deprecated and will eventually be dropped. We used it to avoid PAM in the SDK, but we should have used util-linux's for the production image to begin with. We don't actually need su in the SDK though as sudo does the job, so just drop it from there entirely. Signed-off-by: James Le Cuirot --- build_packages | 2 +- changelog/changes/2026-10-02-su.md | 1 + .../profiles/coreos/base/package.use | 10 ---------- .../profiles/coreos/targets/sdk/package.use | 3 +++ sdk_lib/sdk_entry.sh | 14 +++++++------- 5 files changed, 12 insertions(+), 18 deletions(-) create mode 100644 changelog/changes/2026-10-02-su.md diff --git a/build_packages b/build_packages index eddd8b4595e..f368bf66f43 100755 --- a/build_packages +++ b/build_packages @@ -276,7 +276,7 @@ if [[ "${FLAGS_usepkgonly}" -eq "${FLAGS_FALSE}" ]]; then # dropping USE=pam from sys-apps/systemd requires dropping # USE=systemd from sys-auth/pambase # sys-auth/pambase[sssd] -> sys-auth/sssd -> sys-apps/shadow[pam] -> sys-auth/pambase - break_dep_loop sys-apps/util-linux cryptsetup,pam,systemd,udev \ + break_dep_loop sys-apps/util-linux cryptsetup,pam,su,systemd,udev \ sys-fs/cryptsetup udev \ sys-fs/lvm2 systemd,udev \ sys-apps/systemd audit,cryptsetup,pam,selinux,tpm \ diff --git a/changelog/changes/2026-10-02-su.md b/changelog/changes/2026-10-02-su.md new file mode 100644 index 00000000000..4805e65576b --- /dev/null +++ b/changelog/changes/2026-10-02-su.md @@ -0,0 +1 @@ +- Switched from shadow's su implementation to util-linux's, as the former is deprecated upstream. diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use index 4d020f82b54..c9fb742e9bd 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.use @@ -115,16 +115,6 @@ dev-lang/perl minimal # enables ELF support to e.g. allow tc to handle BPF filters. sys-apps/iproute2 elf -# Enable su for shadow, because shadow >= 4.11 does not have it by default. -# Ideally util-linux should have the su binary, but that is currently not -# possible, because of a bunch of additional dependencies in SDK like -# pam_sssd in baselayout. -# -# Disable su for util-linux to avoid conflict with sys-apps/shadow, which -# has its own su binary. -sys-apps/shadow su -sys-apps/util-linux -su - # Enable kerberos support for NFS net-fs/nfs-utils junction kerberos ldap libmount nfsv3 nfsv4 uuid net-libs/libtirpc kerberos diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use index 702d47ca6e6..614123e8a61 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use @@ -21,3 +21,6 @@ virtual/zlib static-libs # Needed for signed sysexts using systemd-repart sys-apps/systemd cryptsetup + +# Don't include su because it requires PAM, which we don't want in the SDK. +sys-apps/util-linux -su diff --git a/sdk_lib/sdk_entry.sh b/sdk_lib/sdk_entry.sh index 887015e2f48..2ca5108cfdf 100755 --- a/sdk_lib/sdk_entry.sh +++ b/sdk_lib/sdk_entry.sh @@ -48,7 +48,7 @@ sed -i -r '/^masters =/s/\bcoreos(\s|$)/coreos-overlay\1/g' /usr/local/portage/c echo echo "Updating board support in '/build/${target}' to use package cache for version '${version}'" echo "---" - sudo su sdk -l -c "/home/sdk/trunk/src/scripts/setup_board --board='$target' --regen_configs_only" + sudo sudo -u sdk -i /home/sdk/trunk/src/scripts/setup_board --board="$target" --regen_configs_only echo "TARGET_FLATCAR_VERSION='${version}'" | sudo tee "/build/$target/etc/target-version.txt" >/dev/null done fi @@ -76,11 +76,11 @@ if ! grep -q 'export MODULE_SIGNING_KEY_DIR=' /home/sdk/.bashrc; then : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then # For official builds, use ephemeral keys - MODULE_SIGNING_KEY_DIR=$(su sdk -c "mktemp -d") + MODULE_SIGNING_KEY_DIR=$(sudo -u sdk mktemp -d) else # For unofficial builds, use persistent directory MODULE_SIGNING_KEY_DIR="/home/sdk/.module-signing-keys" - su sdk -c "mkdir -p ${MODULE_SIGNING_KEY_DIR@Q}" + sudo -u sdk mkdir -p "${MODULE_SIGNING_KEY_DIR}" fi if [[ ! ${MODULE_SIGNING_KEY_DIR} || ! -d ${MODULE_SIGNING_KEY_DIR} ]]; then echo "Failed to create directory for module signing keys." @@ -104,10 +104,10 @@ grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { # Pre-set via environment (e.g. .sdkenv) — use as-is : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then - SYSEXT_SIGNING_KEY_DIR=$(su sdk -c "mktemp -d") + SYSEXT_SIGNING_KEY_DIR=$(sudo -u sdk mktemp -d) else SYSEXT_SIGNING_KEY_DIR="/home/sdk/.sysext-signing-keys" - su sdk -c "mkdir -p ${SYSEXT_SIGNING_KEY_DIR@Q}" + sudo -u sdk mkdir -p "${SYSEXT_SIGNING_KEY_DIR}" fi if [[ ! "$SYSEXT_SIGNING_KEY_DIR" || ! -d "$SYSEXT_SIGNING_KEY_DIR" ]]; then echo "Failed to create directory for sysext signing keys." @@ -118,14 +118,14 @@ grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { build_id=$(source "/mnt/host/source/.repo/manifests/version.txt"; echo "$FLATCAR_BUILD_ID") # Generate sysext signing key only if missing or empty if [[ ! -s sysexts.key || ! -s sysexts.crt ]]; then - su sdk -c "openssl req -new -nodes -utf8 \ + sudo -u sdk openssl req -new -nodes -utf8 \ -x509 -batch -sha256 \ -days 36000 \ -outform PEM \ -out sysexts.crt \ -keyout sysexts.key \ -newkey 4096 \ - -subj '/CN=Flatcar sysext key/OU=$build_id'" \ + -subj "/CN=Flatcar sysext key/OU=$build_id" \ || echo "Generating sysext signing key failed" fi popd > /dev/null From 5edeca3e77f80b2b731cb2a0f401a3c16dd9d268 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 7 Sep 2026 16:28:32 +0100 Subject: [PATCH 04/11] common.sh: Drop unused load_environment_allowlist() function Signed-off-by: James Le Cuirot --- common.sh | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/common.sh b/common.sh index c209e2ff490..ce6472922ab 100644 --- a/common.sh +++ b/common.sh @@ -256,32 +256,6 @@ get_gclient_root() { fi } -# Populate the ENVIRONMENT_ALLOWLIST array. -load_environment_allowlist() { - ENVIRONMENT_ALLOWLIST=( - COREOS_OFFICIAL - FLATCAR_BUILD_ID - FORCE_STAGES - GIT_AUTHOR_EMAIL - GIT_AUTHOR_NAME - GIT_COMMITTER_EMAIL - GIT_COMMITTER_NAME - GIT_PROXY_COMMAND - GIT_SSH - RSYNC_PROXY - GNUPGHOME - GPG_AGENT_INFO - SSH_AGENT_PID - SSH_AUTH_SOCK - USE - all_proxy - ftp_proxy - http_proxy - https_proxy - no_proxy - ) -} - load_environment_var() { local file="$1"; shift unset "${@}" From 1d63181c44dbf5a6fac0b6fffa045f03a9e7cf75 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 14 Sep 2026 12:43:22 +0100 Subject: [PATCH 05/11] Drop the .sdkenv file by passing env vars with docker exec instead Writing potentially sensitive environment variables to an on-disk shell snippet is not a good idea. It's also unnecessary. Passing the environment variables to `docker run` bakes the values in at container creation time, but passing them to `docker exec` instead allows them to stay current when starting run_sdk_container. The list of environment variables is now split into those we just want to keep when using sudo and those we also want to pass through to the SDK container. These lists are used to generate the sudo `env_keep` value when the SDK is built. This drops a lot of the Google SDK setup, but none of this works anyway, and the rest will be completely dropped soon. This also fixes the GPG agent pass-through. Signed-off-by: James Le Cuirot --- .gitignore | 1 - run_sdk_container | 25 +++--- sdk_lib/90_env_keep | 9 --- sdk_lib/Dockerfile.sdk-import | 11 ++- sdk_lib/env_keep.txt | 3 + sdk_lib/env_pass.txt | 25 ++++++ sdk_lib/sdk_container_common.sh | 139 ++++---------------------------- sdk_lib/sdk_entry.sh | 12 ++- 8 files changed, 70 insertions(+), 155 deletions(-) delete mode 100644 sdk_lib/90_env_keep create mode 100644 sdk_lib/env_keep.txt create mode 100644 sdk_lib/env_pass.txt diff --git a/.gitignore b/.gitignore index c0750870e1b..b347671aa34 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ # SDK container env passing helpers sdk_container/.env -sdk_container/.sdkenv ci-cleanup.sh # build cache / artefacts directories diff --git a/run_sdk_container b/run_sdk_container index 2943d689f7d..5032b939e8e 100755 --- a/run_sdk_container +++ b/run_sdk_container @@ -103,11 +103,6 @@ fi stat=$(call_docker ps --all --no-trunc --filter name="${filter}${name}\$" --format '{{.Status}}' \ | cut -f1 -d' ') -# pass SDK related environment variables and gcloud auth -# into container -setup_sdk_env -setup_gsutil - mkdir -p "__build__/images" mkdir -p "sdk_container/.cache/sdks" @@ -121,8 +116,8 @@ fi if [[ -z ${stat} ]] ; then yell "Creating a new container '$name'" - gpg_volumes=() - gnupg_ssh_gcloud_mount_opts gpg_volumes + credential_args=() + credential_docker_args credential_args if [[ -z ${custom_image} ]]; then ( @@ -145,7 +140,7 @@ if [[ -z ${stat} ]] ; then -v "${PWD}/sdk_container:/mnt/host/source/" -v "${PWD}/__build__/images:/mnt/host/source/src/build" -v "${PWD}:/mnt/host/source/src/scripts" - "${gpg_volumes[@]}" + "${credential_args[@]}" "${mounts[@]}" --privileged --network host @@ -173,6 +168,14 @@ if [[ ${stat} != "Up" ]] ; then fi # Workaround: The SDK expects to be able to write to /etc/hosts -call_docker exec "${name}" sh -c 'cp /etc/hosts /etc/hosts2; umount /etc/hosts ; mv /etc/hosts2 /etc/hosts' - -call_docker exec "${tty[@]}" -i "${name}" /mnt/host/source/src/scripts/sdk_lib/sdk_entry.sh "$@" +call_docker exec -i "${name}" sh <> /home/sdk/.bash # user and SDK environment variables pass-through into container RUN echo "if [ -f /mnt/host/source/.env ]; then source /mnt/host/source/.env; fi" >> /home/sdk/.bashrc -RUN echo "if [ -f /mnt/host/source/.sdkenv ]; then source /mnt/host/source/.sdkenv; fi" >> /home/sdk/.bashrc RUN chown -h sdk:sdk /mnt/host/source/src/scripts /mnt/host/source/src/build /home/sdk/trunk /home/sdk/.bashrc diff --git a/sdk_lib/env_keep.txt b/sdk_lib/env_keep.txt new file mode 100644 index 00000000000..9e6fa9f0f5d --- /dev/null +++ b/sdk_lib/env_keep.txt @@ -0,0 +1,3 @@ +FEATURES +PORTAGE_USERNAME +USE diff --git a/sdk_lib/env_pass.txt b/sdk_lib/env_pass.txt new file mode 100644 index 00000000000..913f42ad344 --- /dev/null +++ b/sdk_lib/env_pass.txt @@ -0,0 +1,25 @@ +all_proxy +COREOS_OFFICIAL +EMAIL +FLATCAR_BUILD_ID +FORCE_STAGES +ftp_proxy +GIT_AUTHOR_EMAIL +GIT_AUTHOR_NAME +GIT_COMMITTER_EMAIL +GIT_COMMITTER_NAME +GIT_PROXY_COMMAND +GIT_SSH +GPG_AGENT_INFO +http_proxy +https_proxy +MODULE_SIGNING_KEY_DIR +no_proxy +RSYNC_PROXY +SBSIGN_CERT +SBSIGN_DB_CERT +SBSIGN_DB_KEY +SBSIGN_KEY +SHIM_SIGNING_CERTIFICATE +SIGNER +SYSEXT_SIGNING_KEY_DIR diff --git a/sdk_lib/sdk_container_common.sh b/sdk_lib/sdk_container_common.sh index d1514a5f72b..b44fd7f6198 100644 --- a/sdk_lib/sdk_container_common.sh +++ b/sdk_lib/sdk_container_common.sh @@ -9,7 +9,6 @@ # sdk_container_common_versionfile="sdk_container/.repo/manifests/version.txt" sdk_container_common_registry="ghcr.io/flatcar" -sdk_container_common_env_file="sdk_container/.sdkenv" # Check for podman and docker; use docker if present, podman alternatively. # Podman needs 'sudo' since we need privileged containers for the SDK. @@ -34,7 +33,7 @@ fi docker_a=( docker ) if "${is_podman}"; then - docker_a=( sudo podman ) + docker_a=( sudo -E podman ) fi docker=${docker_a[*]} @@ -180,138 +179,32 @@ EOF } # -- -# -# Set up SDK environment variables. -# Environment vars are put in a file that is sourced by the container's -# .bashrc (if present). GNUPGHOME and SSH_AUTH_SOCK are set -# to container-specific paths if applicable. - -function setup_sdk_env() { - local var - - rm -f "$sdk_container_common_env_file" - - # conditionally set up gnupg, ssh socket, and gcloud auth / boto - # depending on availability on the host - GNUPGHOME="${GNUPGHOME:-$HOME/.gnupg}" - if [ -d "${GNUPGHOME}" ] ; then - echo "GNUPGHOME=\"/home/sdk/.gnupg\"" >> "$sdk_container_common_env_file" - echo "export GNUPGHOME" >> "$sdk_container_common_env_file" - export GNUPGHOME - fi - - if [ -e "${SSH_AUTH_SOCK:-}" ] ; then - local sockname="$(basename "${SSH_AUTH_SOCK}")" - echo "SSH_AUTH_SOCK=\"/run/sdk/ssh/$sockname\"" >> "$sdk_container_common_env_file" - echo "export SSH_AUTH_SOCK" >> "$sdk_container_common_env_file" - fi - - # keep in sync with 90_env_keep, without GNUPGHOME and - # SSH_AUTH_SOCK as those are set up above, and without BOTO_PATH - # and GOOGLE_APPLICATION_CREDENTIALS as those are set up in the - # setup_gsutil function. - for var in FLATCAR_BUILD_ID COREOS_OFFICIAL \ - EMAIL GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME \ - GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME \ - GIT_PROXY_COMMAND GIT_SSH RSYNC_PROXY \ - GPG_AGENT_INFO \ - \ - USE FEATURES PORTAGE_USERNAME FORCE_STAGES \ - SIGNER \ - SBSIGN_KEY SBSIGN_CERT SBSIGN_DB_KEY SBSIGN_DB_CERT \ - SHIM_SIGNING_CERTIFICATE \ - MODULE_SIGNING_KEY_DIR SYSEXT_SIGNING_KEY_DIR \ - all_proxy ftp_proxy http_proxy https_proxy no_proxy; do - - if [ -n "${!var:-}" ] ; then - echo "${var}=\"${!var}\"" >> "$sdk_container_common_env_file" - echo "export ${var}" >> "$sdk_container_common_env_file" - fi - done -} -# -- - -# Set up gcloud legacy creds (via GOOGLE_APPLICATION_CREDENTIALS) -# for the SDK container. -# This will also create a boto config right next to the -# GOOGLE_APPLICATION_CREDENTIALS json file. - -function setup_gsutil() { - local creds="${GOOGLE_APPLICATION_CREDENTIALS:-$HOME/.config/gcloud/application_default_credentials.json}" - if [ ! -e "$creds" ]; then - return - fi - - local creds_dir="$(dirname "$creds")" - local botofile="$creds_dir/boto-flatcar-sdk" - - # TODO t-lo: move generation of boto file to sdk_entry so - # it's only created inside the container. - - # read creds file and create boto file for gsutil - local tmp="$(mktemp)" - trap "rm -f '$tmp'" EXIT - - local oauth_refresh="$(jq -r '.refresh_token' "$creds")" - local client_id="$(jq -r '.client_id' "$creds")" - local client_secret="$(jq -r '.client_secret' "$creds")" - - cat >>"$tmp" <> "$sdk_container_common_env_file" - echo "export BOTO_PATH" >> "$sdk_container_common_env_file" - echo "GOOGLE_APPLICATION_CREDENTIALS=\"$creds\"" >> "$sdk_container_common_env_file" - echo "export GOOGLE_APPLICATION_CREDENTIALS" >> "$sdk_container_common_env_file" - - BOTO_PATH="$botofile" - GOOGLE_APPLICATION_CREDENTIALS="$creds" - export BOTO_PATH - export GOOGLE_APPLICATION_CREDENTIALS -} - -# -- - -# Generate volume mount command line options for docker -# to pass gpg, ssh, and gcloud auth host directories -# into the SDK container. - -function gnupg_ssh_gcloud_mount_opts() { +# Generate command line options for Docker to pass GPG and SSH host directories +# into the SDK container. +function credential_docker_args() { local -n args_ref="${1}"; shift + args_ref=() local sdk_gnupg_home="/home/sdk/.gnupg" - local gpgagent_dir="/run/user/$(id -u)/gnupg" + local gpgagent_dir="/run/user/${UID}/gnupg" - args_ref=() # pass host GPG home and Agent directories to container - if [[ -d ${GNUPGHOME} ]] ; then - args_ref+=( -v "$GNUPGHOME:$sdk_gnupg_home" ) + : "${GNUPGHOME:="${HOME}"/.gnupg}" + if [[ -d ${GNUPGHOME:-} ]] ; then + args_ref+=( + -v "$GNUPGHOME:$sdk_gnupg_home" + -e GNUPGHOME="$sdk_gnupg_home" + ) fi if [[ -d ${gpgagent_dir} ]] ; then args_ref+=( -v "${gpgagent_dir}:${gpgagent_dir}" ) fi - local sshsockdir if [[ -e ${SSH_AUTH_SOCK:-} ]] ; then - sshsockdir=$(dirname "$SSH_AUTH_SOCK") - args_ref+=( -v "${sshsockdir}:/run/sdk/ssh" ) - fi - - local creds_dir - if [[ -e ${GOOGLE_APPLICATION_CREDENTIALS:-} ]] ; then - creds_dir=$(dirname "${GOOGLE_APPLICATION_CREDENTIALS}") - if [[ -d ${creds_dir} ]] ; then - echo "Mounting gcloud credentials from ${creds_dir} (used for artifact uploads, safe to ignore if not needed, not baked into any image)" - echo "-v $creds_dir:$creds_dir" - args_ref+=( -v "${creds_dir}:${creds_dir}" ) - fi + args_ref+=( + -v "${SSH_AUTH_SOCK%/*}:/run/sdk/ssh" + -e SSH_AUTH_SOCK="/run/sdk/ssh/${SSH_AUTH_SOCK##*/}" + ) fi } diff --git a/sdk_lib/sdk_entry.sh b/sdk_lib/sdk_entry.sh index 2ca5108cfdf..98f65798dd2 100755 --- a/sdk_lib/sdk_entry.sh +++ b/sdk_lib/sdk_entry.sh @@ -1,10 +1,5 @@ #!/bin/bash -# Source SDK environment variables if available (includes COREOS_OFFICIAL, etc.) -if [ -f /mnt/host/source/.sdkenv ]; then - source /mnt/host/source/.sdkenv -fi - if [ -n "${SDK_USER_ID:-}" ] ; then # If the "core" user from /usr/share/baselayout/passwd has the same ID, allow to take it instead usermod --non-unique -u $SDK_USER_ID sdk @@ -15,6 +10,9 @@ fi chown -R sdk:sdk /home/sdk +# GPG won't use the socket dir if /var/run/${UID} has the wrong permissions. +install -o sdk -g sdk -m 0700 -d "/run/user/$(id -u sdk)" + # Fix up SDK repo configuration to use the new coreos-overlay name. sed -i -r 's/^\[coreos\]/[coreos-overlay]/' /etc/portage/repos.conf/coreos.conf 2>/dev/null sed -i -r '/^masters =/s/\bcoreos(\s|$)/coreos-overlay\1/g' /usr/local/portage/crossdev/metadata/layout.conf 2>/dev/null @@ -72,7 +70,7 @@ fi # Create key directory if not already configured in .bashrc if ! grep -q 'export MODULE_SIGNING_KEY_DIR=' /home/sdk/.bashrc; then if [[ -n ${MODULE_SIGNING_KEY_DIR:-} ]]; then - # Pre-set via environment (e.g. .sdkenv) — use as-is + # Pre-set via environment — use as-is : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then # For official builds, use ephemeral keys @@ -101,7 +99,7 @@ if grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc; then fi grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { if [[ -n ${SYSEXT_SIGNING_KEY_DIR:-} ]]; then - # Pre-set via environment (e.g. .sdkenv) — use as-is + # Pre-set via environment — use as-is : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then SYSEXT_SIGNING_KEY_DIR=$(sudo -u sdk mktemp -d) From 25669798a25dcf3347912f8597bacba7ae381024 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Wed, 30 Sep 2026 17:36:54 +0100 Subject: [PATCH 06/11] ci-automation: Drop unused PXE_KERNEL_NAME and PXE_IMAGE_NAME These were used by the Equinix Metal testing script. Signed-off-by: James Le Cuirot --- ci-automation/ci-config.env | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ci-automation/ci-config.env b/ci-automation/ci-config.env index bb9990591e7..b5d4c6ebde5 100644 --- a/ci-automation/ci-config.env +++ b/ci-automation/ci-config.env @@ -81,10 +81,6 @@ QEMU_DEVCONTAINER_URL="${QEMU_DEVCONTAINER_URL:-}" QEMU_DEVCONTAINER_BINHOST_URL="${QEMU_DEVCONTAINER_BINHOST_URL:-}" QEMU_DEVCONTAINER_FILE="${QEMU_DEVCONTAINER_FILE:-}" -# -- PXE -- -PXE_KERNEL_NAME="flatcar_production_pxe.vmlinuz" -PXE_IMAGE_NAME="flatcar_production_pxe_image.cpio.gz" - GCE_IMAGE_NAME="flatcar_production_gce.tar.gz" GCE_GCS_IMAGE_UPLOAD="gs://flatcar-jenkins/developer/gce-ci" GCE_MACHINE_TYPE="${GCE_MACHINE_TYPE:-n1-standard-2}" From c1ce7877549a9f7d991e03f5f7e9eac124b0c90b Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Thu, 1 Oct 2026 18:48:53 +0100 Subject: [PATCH 07/11] ci-automation: Don't pass Azure credentials as command line arguments Docker can pass these through by name without the values. Signed-off-by: James Le Cuirot --- ci-automation/release/azure_marketplace.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ci-automation/release/azure_marketplace.sh b/ci-automation/release/azure_marketplace.sh index 6ec48822b8e..f628570603a 100644 --- a/ci-automation/release/azure_marketplace.sh +++ b/ci-automation/release/azure_marketplace.sh @@ -42,12 +42,13 @@ function _release_azure_marketplace_impl() { AZ_TENANT_ID=$(secret_from_base64 "AZ_TENANT_ID" "${AZ_MARKETPLACE_PUBLISH}") AZ_CLIENT_ID=$(secret_from_base64 "AZ_CLIENT_ID" "${AZ_MARKETPLACE_PUBLISH}") AZ_SECRET_VALUE=$(secret_from_base64 "AZ_SECRET_VALUE" "${AZ_MARKETPLACE_PUBLISH}") + export AZ_STORAGE_KEY AZ_TENANT_ID AZ_CLIENT_ID AZ_SECRET_VALUE docker run --pull always --rm --name="${container_name}" --net host \ - -e AZ_STORAGE_KEY="${AZ_STORAGE_KEY}" \ - -e AZ_TENANT_ID="${AZ_TENANT_ID}" \ - -e AZ_CLIENT_ID="${AZ_CLIENT_ID}" \ - -e AZ_SECRET_VALUE="${AZ_SECRET_VALUE}" \ + -e AZ_STORAGE_KEY \ + -e AZ_TENANT_ID \ + -e AZ_CLIENT_ID \ + -e AZ_SECRET_VALUE \ -v "${PWD}"/ci-automation/release/azure_marketplace_publish.py:/app/azure_marketplace_publish.py \ -w /app \ ghcr.io/flatcar/uv:alpine \ From 17feee6dbd60e2944d23681972603b693cc45c11 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Mon, 5 Oct 2026 10:45:33 +0100 Subject: [PATCH 08/11] ci-automation: Use here strings to avoid showing credentials with set -x Signed-off-by: James Le Cuirot --- ci-automation/garbage_collect_cloud.sh | 6 +++--- ci-automation/vendor-testing/stackit.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci-automation/garbage_collect_cloud.sh b/ci-automation/garbage_collect_cloud.sh index 68a3edfb2c1..4ebfa107ed0 100755 --- a/ci-automation/garbage_collect_cloud.sh +++ b/ci-automation/garbage_collect_cloud.sh @@ -2,14 +2,14 @@ set -euo pipefail source ci-automation/ci_automation_common.sh timeout --signal=SIGQUIT 60m ore aws gc --access-id "${AWS_ACCESS_KEY_ID}" --secret-key "${AWS_SECRET_ACCESS_KEY}" -timeout --signal=SIGQUIT 60m ore gcloud gc --json-key <(echo "${GCP_JSON_KEY}" | base64 --decode) +timeout --signal=SIGQUIT 60m ore gcloud gc --json-key <(base64 --decode <<< "${GCP_JSON_KEY}") timeout --signal=SIGQUIT 60m ore azure gc --duration 6h timeout --signal=SIGQUIT 60m ore brightbox gc --duration 6h \ --brightbox-client-id="${BRIGHTBOX_CLIENT_ID}" --brightbox-client-secret="${BRIGHTBOX_CLIENT_SECRET}" timeout --signal=SIGQUIT 60m ore akamai gc --duration 6h \ --akamai-token="${AKAMAI_TOKEN}" timeout --signal=SIGQUIT 60m ore stackit gc --duration 6h \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" secret_to_file aws_credentials_config_file "${AWS_CREDENTIALS}" for channel in alpha beta stable lts; do @@ -29,5 +29,5 @@ timeout --signal=SIGQUIT 60m ore oraclecloud gc --duration 6h \ --oraclecloud-tenancy="${ORACLECLOUD_TENANCY}" \ --oraclecloud-user="${ORACLECLOUD_USER}" \ --oraclecloud-fingerprint="${ORACLECLOUD_FINGERPRINT}" \ - --oraclecloud-private-key="$(echo "${ORACLECLOUD_PRIVATE_KEY}" | base64 --decode)" \ + --oraclecloud-private-key="$(base64 --decode <<< "${ORACLECLOUD_PRIVATE_KEY}")" \ --oraclecloud-compartment-id="${ORACLECLOUD_COMPARTMENT_ID}" diff --git a/ci-automation/vendor-testing/stackit.sh b/ci-automation/vendor-testing/stackit.sh index ea8c30e31bb..aa23cd05c2b 100755 --- a/ci-automation/vendor-testing/stackit.sh +++ b/ci-automation/vendor-testing/stackit.sh @@ -22,7 +22,7 @@ kola_test_basename="ci-${CIA_VERNUM//[+.]/-}" # Upload the image on STACKIT. IMAGE_ID=$(ore stackit \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" \ create-image \ --board "${CIA_ARCH}-usr" \ @@ -39,7 +39,7 @@ timeout --signal=SIGQUIT 2h kola run \ --channel="${CIA_CHANNEL}" \ --basename="${kola_test_basename}" \ --platform=stackit \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" \ --stackit-image-id="${IMAGE_ID}" \ --stackit-type="${stackit_instance_type}" \ From d1de2636bd981e942653a5b8908c8fba022d4253 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Thu, 1 Oct 2026 18:27:09 +0100 Subject: [PATCH 09/11] ci-automation: Simplify the test launcher with bash arguments Signed-off-by: James Le Cuirot --- ci-automation/test.sh | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/ci-automation/test.sh b/ci-automation/test.sh index c8db48edd01..a83bca8435c 100644 --- a/ci-automation/test.sh +++ b/ci-automation/test.sh @@ -72,21 +72,6 @@ # script would need to make anyway. For more information, please refer # to the vendor_test.sh file. -function __escape_multiple() { - local out_array_arg_name="${1}"; shift - # rest are args to be escape and appended into the array named - # after the first arg - local -n out_array_arg_ref="${out_array_arg_name}" - local arg arg_escaped - - out_array_arg_ref=() - for arg; do - printf -v arg_escaped '%q' "${arg}" - out_array_arg_ref+=( "${arg_escaped}" ) - done -} -# -- - function test_run() { # Run a subshell, so the traps, environment changes and global # variables are not spilled into the caller. @@ -143,38 +128,28 @@ function _test_run_impl() { # A job on each worker prunes old mantle images (docker image prune) echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - local image_escaped - printf -v image_escaped '%q' "${image}" local common_test_args=( "${work_dir}" "${tests_dir}" "${arch}" "${vernum}" ) - local common_test_args_escaped=() - __escape_multiple common_test_args_escaped "${common_test_args[@]}" - - local tests_escaped=() - __escape_multiple tests_escaped "${@}" # Vendor tests may need to know if it is a first run or a rerun touch "${work_dir}/first_run" for retry in $(seq "${retries}"); do local tapfile="results-run-${retry}.tap" local failfile="failed-run-${retry}.txt" - local tapfile_escaped - printf -v tapfile_escaped '%q' "${tapfile}" # Ignore retcode since tests are flaky. We'll re-run failed tests and # determine success based on test results (tapfile). - set +e touch sdk_container/.env docker run --pull always --rm --name="${container_name}" --privileged --net host -v /dev:/dev \ - -w /work -v "$PWD":/work "${MANTLE_REF}" \ - bash -c "git config --global --add safe.directory /work && \ - source sdk_container/.env && \ - ci-automation/vendor-testing/${image_escaped}.sh ${common_test_args_escaped[*]} ${tapfile_escaped} ${tests_escaped[*]}" - set -e + -w /work -v "$PWD":/work "${MANTLE_REF}" bash -ec \ + 'git config --global --add safe.directory /work + source sdk_container/.env + ci-automation/vendor-testing/"${1}".sh "${@:2}"' \ + -- "${image}" "${common_test_args[@]}" "${tapfile}" "${@}" || : rm -f "${work_dir}/first_run" # Note: git safe.directory is not set in this run as it does not use git @@ -208,7 +183,7 @@ function _test_run_impl() { echo "Failed tests:" printf '%s\n' "${failed_tests[@]}" echo "-----------" - __escape_multiple tests_escaped "${failed_tests[@]}" + set -- "${failed_tests[@]}" done if ${print_give_up}; then From cbf315d2a0d76edda753a7c7472260ef1315216f Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Thu, 1 Oct 2026 19:52:28 +0100 Subject: [PATCH 10/11] Drop the sdk_container/.env file by passing env vars with docker run Writing potentially sensitive environment variables to an on-disk shell snippet is not a good idea. It's also unnecessary. A list of these Mantle-specific variables now live in a text file that can be passed to `docker run`, allowing all of them to be passed through directly. Flatcar's Jenkins scripts also used .env to set arbitrary variables and potentially run other commands. This is now supported via standard input to the test_run function. Signed-off-by: James Le Cuirot --- .github/workflows/run-kola-tests.yaml | 2 -- .gitignore | 3 +- build_sdk_container_image | 2 +- ci-automation/ci-config.env | 13 ++------ ci-automation/garbage_collect.sh | 16 +--------- ci-automation/release.sh | 8 ++--- ci-automation/release/azure_marketplace.sh | 1 - ci-automation/test.sh | 11 ++++--- ci-automation/vendor-testing/brightbox.sh | 2 +- ci-automation/vendor-testing/hetzner.sh | 2 +- ci-automation/vendor-testing/openstack.sh | 2 +- run_local_tests.sh | 23 ++++++-------- sdk_lib/Dockerfile.sdk-build | 6 +--- sdk_lib/Dockerfile.sdk-import | 3 -- sdk_lib/env_mantle.txt | 37 ++++++++++++++++++++++ 15 files changed, 66 insertions(+), 65 deletions(-) create mode 100644 sdk_lib/env_mantle.txt diff --git a/.github/workflows/run-kola-tests.yaml b/.github/workflows/run-kola-tests.yaml index f2da99351f2..7cf4dad3ed0 100644 --- a/.github/workflows/run-kola-tests.yaml +++ b/.github/workflows/run-kola-tests.yaml @@ -182,7 +182,6 @@ jobs: PARALLEL_ARCH=5 - cat > sdk_container/.env < sdk_container/.env -# in your CI to override, e.g. -# echo "export PARALLEL_TESTS=\"5\"" > sdk_container/.env -# to override the number of test cases to be run in parallel. # -- General -- @@ -95,13 +90,13 @@ GCE_PARALLEL="${PARALLEL_TESTS:-4}" : ${DIGITALOCEAN_MACHINE_SIZE:='s-2vcpu-2gb'} DIGITALOCEAN_PARALLEL="${PARALLEL_TESTS:-8}" # DIGITALOCEAN_TOKEN_JSON env var is used for credentials, and should -# come from sdk_container/.env. It must be base64-encoded. +# come from the caller. It must be base64-encoded. # -- VMware ESX -- : ${VMWARE_ESX_IMAGE_NAME:='flatcar_production_vmware_ova.ova'} VMWARE_ESX_PARALLEL="${PARALLEL_TESTS:-4}" -# VMWARE_ESX_CREDS should come from sdk_container/.env and must be +# VMWARE_ESX_CREDS should come from the caller and must be # base64-encoded. # -- AWS -- @@ -118,8 +113,7 @@ VMWARE_ESX_PARALLEL="${PARALLEL_TESTS:-4}" : ${AWS_REGION:="us-east-1"} : ${AWS_AMI_ID:=""} AWS_PARALLEL="${PARALLEL_TESTS:-8}" -# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should come from -# sdk_container/.env +# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should come from the caller. # -- Azure -- : ${AZURE_IMAGE_NAME:="flatcar_production_azure_image.vhd"} @@ -128,7 +122,6 @@ AWS_PARALLEL="${PARALLEL_TESTS:-8}" : ${AZURE_USE_GALLERY:=""} : ${AZURE_KOLA_VNET:=""} : ${AZURE_USE_PRIVATE_IPS:=true} -: ${AZURE_VNET_SUBNET_NAME:="jenkins-vnet-westeurope"} AZURE_PARALLEL="${PARALLEL_TESTS:-20}" AZURE_LOCATION="${AZURE_LOCATION:-westeurope}" diff --git a/ci-automation/garbage_collect.sh b/ci-automation/garbage_collect.sh index 1d33dc8dc2c..850907d852b 100644 --- a/ci-automation/garbage_collect.sh +++ b/ci-automation/garbage_collect.sh @@ -255,21 +255,7 @@ function _garbage_collect_impl() { local mantle_ref mantle_ref=$(cat sdk_container/.repo/manifests/mantle-container) - docker run --pull always --rm --net host \ - --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY \ - --env AWS_CREDENTIALS \ - --env DIGITALOCEAN_TOKEN_JSON \ - --env GCP_JSON_KEY \ - --env VMWARE_ESX_CREDS \ - --env BRIGHTBOX_CLIENT_ID --env BRIGHTBOX_CLIENT_SECRET \ - --env AKAMAI_TOKEN \ - --env STACKIT_SERVICE_ACCOUNT \ - --env STACKIT_PROJECT_ID \ - --env ORACLECLOUD_TENANCY \ - --env ORACLECLOUD_USER \ - --env ORACLECLOUD_FINGERPRINT \ - --env ORACLECLOUD_PRIVATE_KEY \ - --env ORACLECLOUD_COMPARTMENT_ID \ + docker run --pull always --rm --net host --env-file="sdk_lib/env_mantle.txt" \ -w /work -v "$PWD":/work "${mantle_ref}" /work/ci-automation/garbage_collect_cloud.sh echo diff --git a/ci-automation/release.sh b/ci-automation/release.sh index 4d3bc483c82..678fde80341 100644 --- a/ci-automation/release.sh +++ b/ci-automation/release.sh @@ -75,8 +75,6 @@ function _inside_mantle() { source sdk_lib/sdk_container_common.sh source ci-automation/ci_automation_common.sh source sdk_container/.repo/manifests/version.txt - # Needed because we are not the SDK container here - source sdk_container/.env CHANNEL="$(get_git_channel)" VERSION="${FLATCAR_VERSION}" aws_credentials_config_file="" @@ -240,8 +238,6 @@ function _release_build_impl() { source ci-automation/gpg_setup.sh source sdk_container/.repo/manifests/version.txt - # Needed because we are not the SDK container here - source sdk_container/.env local sdk_version="${FLATCAR_SDK_VERSION}" local docker_sdk_vernum="" docker_sdk_vernum="$(vernum_to_docker_image_version "${sdk_version}")" @@ -257,9 +253,9 @@ function _release_build_impl() { # A job on each worker prunes old mantle images (docker image prune), no need to do it here echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - touch sdk_container/.env # This file should already contain the required credentials as env vars docker run --pull always --rm --name="${container_name}" --net host \ - -w /work -v "$PWD":/work "${mantle_ref}" bash -c "git config --global --add safe.directory /work && source ci-automation/release.sh && _inside_mantle" + -w /work -v "$PWD":/work --env-file="sdk_lib/env_mantle.txt" "${mantle_ref}" \ + bash -c "git config --global --add safe.directory /work && source ci-automation/release.sh && _inside_mantle" # Push flatcar_production_ami_*txt and flatcar_production_ami_*json to the right bincache folder for arch in amd64 arm64; do sudo chown -R "$USER:$USER" "aws-${arch}" diff --git a/ci-automation/release/azure_marketplace.sh b/ci-automation/release/azure_marketplace.sh index f628570603a..0b9b50e9367 100644 --- a/ci-automation/release/azure_marketplace.sh +++ b/ci-automation/release/azure_marketplace.sh @@ -37,7 +37,6 @@ function _release_azure_marketplace_impl() { # A job on each worker prunes old mantle images (docker image prune), no need to do it here echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - source sdk_container/.env AZ_STORAGE_KEY=$(secret_from_base64 "AZ_STORAGE_KEY" "${AZ_MARKETPLACE_PUBLISH}") AZ_TENANT_ID=$(secret_from_base64 "AZ_TENANT_ID" "${AZ_MARKETPLACE_PUBLISH}") AZ_CLIENT_ID=$(secret_from_base64 "AZ_CLIENT_ID" "${AZ_MARKETPLACE_PUBLISH}") diff --git a/ci-automation/test.sh b/ci-automation/test.sh index a83bca8435c..9f694500c1a 100644 --- a/ci-automation/test.sh +++ b/ci-automation/test.sh @@ -33,6 +33,7 @@ # # 3. List of tests / test patterns. Defaults to "*" (all tests). # All positional arguments after the first 2 (see above) are tests / patterns of tests to run. +# 4. Standard input. Use this to run arbitrary commands inside container before starting the tests. # # MAX_RETRIES. Environment variable. Number of re-runs to overcome transient failures. Defaults to 20. # PARALLEL_TESTS. Environment variable. Number of test cases to run in parallel. @@ -135,6 +136,9 @@ function _test_run_impl() { "${vernum}" ) + local stdin="" + [[ ! -t 0 ]] && stdin=$(< /dev/stdin) + # Vendor tests may need to know if it is a first run or a rerun touch "${work_dir}/first_run" for retry in $(seq "${retries}"); do @@ -143,13 +147,12 @@ function _test_run_impl() { # Ignore retcode since tests are flaky. We'll re-run failed tests and # determine success based on test results (tapfile). - touch sdk_container/.env docker run --pull always --rm --name="${container_name}" --privileged --net host -v /dev:/dev \ - -w /work -v "$PWD":/work "${MANTLE_REF}" bash -ec \ + -w /work -v "$PWD":/work --env-file="sdk_lib/env_mantle.txt" -i "${MANTLE_REF}" bash -ec \ 'git config --global --add safe.directory /work - source sdk_container/.env + source /dev/stdin ci-automation/vendor-testing/"${1}".sh "${@:2}"' \ - -- "${image}" "${common_test_args[@]}" "${tapfile}" "${@}" || : + -- "${image}" "${common_test_args[@]}" "${tapfile}" "${@}" <<< "${stdin}" || : rm -f "${work_dir}/first_run" # Note: git safe.directory is not set in this run as it does not use git diff --git a/ci-automation/vendor-testing/brightbox.sh b/ci-automation/vendor-testing/brightbox.sh index e18a9153c83..8d520554e52 100755 --- a/ci-automation/vendor-testing/brightbox.sh +++ b/ci-automation/vendor-testing/brightbox.sh @@ -22,7 +22,7 @@ if [[ "${CIA_ARCH}" == "arm64" ]]; then exit 1 fi -# BRIGHTBOX_CLIENT_ID, BRIGHTBOX_CLIENT_SECRET should be provided by sdk_container/.env +# BRIGHTBOX_CLIENT_ID, BRIGHTBOX_CLIENT_SECRET should be provided by the caller. # Upload the image on Brightbox. IMAGE_ID=$(ore brightbox create-image \ diff --git a/ci-automation/vendor-testing/hetzner.sh b/ci-automation/vendor-testing/hetzner.sh index 167670ddeb0..0ea602e396b 100755 --- a/ci-automation/vendor-testing/hetzner.sh +++ b/ci-automation/vendor-testing/hetzner.sh @@ -16,7 +16,7 @@ hetzner_instance_type="${!hetzner_instance_type_var}" hetzner_location_var="HETZNER_${CIA_ARCH}_LOCATION" hetzner_location="${!hetzner_location_var}" -# HETZNER_TPS_TOKEN should be provided by sdk_container/.env +# HETZNER_TPS_TOKEN should be provided by the caller. # We first need to create a temporary project using HETZNER_TPS_TOKEN # When the project is created it returns a regular HETZNER_TOKEN that can be used diff --git a/ci-automation/vendor-testing/openstack.sh b/ci-automation/vendor-testing/openstack.sh index d1a1a4143a9..e780bd90aec 100755 --- a/ci-automation/vendor-testing/openstack.sh +++ b/ci-automation/vendor-testing/openstack.sh @@ -22,7 +22,7 @@ if [[ "${CIA_ARCH}" == "arm64" ]]; then exit 1 fi -# OPENSTACK_CREDS, OPENSTACK_USER, OPENSTACK_HOST, OPENSTACK_KEYFILE should be provided by sdk_container/.env +# OPENSTACK_CREDS, OPENSTACK_USER, OPENSTACK_HOST, OPENSTACK_KEYFILE should be provided by the caller. config_file='' secret_to_file config_file "${OPENSTACK_CREDS}" diff --git a/run_local_tests.sh b/run_local_tests.sh index e4ee0c8a08a..54f69973a3f 100755 --- a/run_local_tests.sh +++ b/run_local_tests.sh @@ -1,11 +1,11 @@ #!/bin/bash # # Copyright (c) 2023 The Flatcar Maintainers. -# Licensed under the Apache License, Version 2.0 (the "License"); +# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # QoL wrapper around ci-automation test.sh for running local tests of qemu_uefi image. # The devcontainer tests will be skipped since these require a valid commit ref in @@ -17,7 +17,7 @@ # Prerequisites: # - Flatcar OS image and qemu uefi code to be tested in # __build__/images/images/amd64-usr/latest/ -# +# # This script is intended to be run after building a qemu_uefi image with the SDK container: # ./build_packages # ./build_image @@ -48,15 +48,12 @@ function set_vars() { local arch="${1}" local parallel="${2}" - # Read by the mantle container. # The local directory ("pwd") will be mounted to /work/ in the container. - cat > sdk_container/.env < /mnt/host/source/.env +ARG COREOS_OFFICIAL=0 RUN FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox" \ /home/sdk/sdk_entry.sh ./sdk_lib/setup_boards.sh start "${BINHOST}" -RUN rm /mnt/host/source/.env RUN rm -rf /home/sdk/toolchain-pkgs # Clean up ephemeral key directory variables that were added during build diff --git a/sdk_lib/Dockerfile.sdk-import b/sdk_lib/Dockerfile.sdk-import index 176ac476ab1..7f3445b25e8 100644 --- a/sdk_lib/Dockerfile.sdk-import +++ b/sdk_lib/Dockerfile.sdk-import @@ -41,9 +41,6 @@ RUN cp /etc/skel/.bashrc /home/sdk RUN echo "cd /home/sdk/trunk/src/scripts" >> /home/sdk/.bashrc RUN echo 'export PATH="$PATH:/usr/local/bin:/usr/local/sbin"' >> /home/sdk/.bashrc -# user and SDK environment variables pass-through into container -RUN echo "if [ -f /mnt/host/source/.env ]; then source /mnt/host/source/.env; fi" >> /home/sdk/.bashrc - RUN chown -h sdk:sdk /mnt/host/source/src/scripts /mnt/host/source/src/build /home/sdk/trunk /home/sdk/.bashrc COPY --chown=sdk:sdk sdk_lib/sdk_entry.sh /home/sdk diff --git a/sdk_lib/env_mantle.txt b/sdk_lib/env_mantle.txt new file mode 100644 index 00000000000..cdb3d5fe432 --- /dev/null +++ b/sdk_lib/env_mantle.txt @@ -0,0 +1,37 @@ +AKAMAI_TOKEN +AWS_ACCESS_KEY_ID +AWS_CLOUDFORMATION_CREDENTIALS +AWS_CREDENTIALS +AWS_IAM_PROFILE +AWS_MARKETPLACE_ARN +AWS_MARKETPLACE_CREDENTIALS +AWS_REGION +AWS_SECRET_ACCESS_KEY +AZURE_LOCATION +AZURE_SUBSCRIPTION_ID +BRIGHTBOX_CLIENT_ID +BRIGHTBOX_CLIENT_SECRET +DIGITALOCEAN_TOKEN_JSON +GCP_JSON_KEY +GOOGLE_RELEASE_CREDENTIALS +HETZNER_TPS_TOKEN +OPENSTACK_CREDS +OPENSTACK_HOST +OPENSTACK_KEYFILE +OPENSTACK_USER +ORACLECLOUD_COMPARTMENT_ID +ORACLECLOUD_FINGERPRINT +ORACLECLOUD_PRIVATE_KEY +ORACLECLOUD_TENANCY +ORACLECLOUD_USER +PARALLEL_TESTS +QEMU_DEVCONTAINER_BINHOST_URL +QEMU_DEVCONTAINER_URL +QEMU_IMAGE_NAME +QEMU_KOLA_SKIP_MANGLE +QEMU_UEFI_FIRMWARE +QEMU_UEFI_OVMF_VARS +QEMU_UPDATE_PAYLOAD +STACKIT_PROJECT_ID +STACKIT_SERVICE_ACCOUNT +VMWARE_ESX_CREDS From 366cb26fea73f7d08194057ada8a7c7613c17eb0 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 2 Oct 2026 17:51:10 +0100 Subject: [PATCH 11/11] run_sdk_container: Add -e option to pass through environment variables This only supports passing through variables by name, not setting their values. While it could easily do this, it would encourage the inclusion of secrets on the command line, which is insecure. Docker's -e option doesn't allow separating multiple names with whitespace, but I thought it would be useful here so that you could do things like -e "${!RCLONE_S3_*}". Signed-off-by: James Le Cuirot --- run_sdk_container | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/run_sdk_container b/run_sdk_container index 5032b939e8e..c6b75f2f4c7 100755 --- a/run_sdk_container +++ b/run_sdk_container @@ -19,6 +19,7 @@ tty=() remove="" cleanup="" mounts=() +envs=() usage() { echo " Usage:" @@ -49,6 +50,8 @@ usage() { echo " -U Do not update the versionfile. Instead, use the version from the versionfile as-is." echo " -m : - Mount local file or directory inside the container." echo " Can be specified multiple times." + echo " -e Space-separated list of environment variable names to pass through." + echo " Can be specified multiple times." echo " -- Stop parsing options at this point, pass the rest as the container command." echo " -h Print this help." echo @@ -73,6 +76,14 @@ while [[ $# -gt 0 ]] ; do update_versionfile= shift;; -m) mounts+=( -v "$2" ); shift; shift;; + -e) if [[ $2 == *=* ]]; then + echo "Do not pass environment variable values to -e, only names." + exit 1 + fi + for var in $2; do + envs+=( --env "${var}" ) + done + shift 2;; --) shift; break;; -*) echo "Unknown flag ${1@Q}, use '-h' or '--help' for usage"; exit 1;; *) break;; @@ -176,6 +187,6 @@ EOF call_docker exec \ --env-file="sdk_lib/env_pass.txt" \ - "${tty[@]}" -i \ + "${envs[@]}" "${tty[@]}" -i \ "${name}" \ /mnt/host/source/src/scripts/sdk_lib/sdk_entry.sh "$@"