From 9bed4c4911e112cc96b29fcb9c1720847946f776 Mon Sep 17 00:00:00 2001 From: davdhacs <105243888+davdhacs@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:18:13 -0600 Subject: [PATCH] Remove cci-export and the bash-wrapper mechanism cci-export persisted environment variables across CircleCI steps by writing to $BASH_ENV, which CircleCI sources before each step's shell. StackRox CI runs on GitHub Actions and OpenShift CI/prow now, where BASH_ENV is never sourced between steps -- cross-step state travels via $GITHUB_ENV and $SHARED_DIR instead -- so the mechanism is dead weight. Removed: - static-contents/bin/bash-wrapper (the cci-export function and the /bin/bash -> /bin/real-bash swap that installed it) - static-contents/etc/initial-bash.env (the BASH_ENV foundation) - images/test.cci-export.Dockerfile and images/test/ (the bats tests) - the ENV BASH_ENV declarations from the test/ui-test images - the test-cci-export Makefile target and the corresponding CI job Consumers (stackrox, scanner) call cci-export behind a `command -v cci-export` guard and fall back to plain `export`, so this change degrades gracefully rather than breaking their CI. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/build.yaml | 16 -- Makefile | 12 -- images/jenkins-plugin.Dockerfile | 7 - images/scanner-test.Dockerfile | 8 - images/stackrox-test.Dockerfile | 7 - images/stackrox-ui-test.Dockerfile | 7 - images/static-contents/bin/bash-wrapper | 64 ------ images/static-contents/etc/initial-bash.env | 2 - images/test.cci-export.Dockerfile | 8 - images/test/bats/cci-export.bats | 204 -------------------- images/test/bats/foo-printer.sh | 23 --- images/test/bats/test-ca.crt | 18 -- 12 files changed, 376 deletions(-) delete mode 100755 images/static-contents/bin/bash-wrapper delete mode 100644 images/static-contents/etc/initial-bash.env delete mode 100644 images/test.cci-export.Dockerfile delete mode 100755 images/test/bats/cci-export.bats delete mode 100755 images/test/bats/foo-printer.sh delete mode 100644 images/test/bats/test-ca.crt diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 71342bcd..91fafa9c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -112,22 +112,6 @@ jobs: path: image-info/${{ matrix.image-flavor }}.txt retention-days: 1 - test-cci-export: - runs-on: ubuntu-latest - needs: - - build-and-push-builder-images - - build-and-push-test-images - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} - - name: Test cci-export in a context similar to how it is used in CI - run: | - docker login -u "$QUAY_STACKROX_IO_RW_USERNAME" --password-stdin <<<"$QUAY_STACKROX_IO_RW_PASSWORD" quay.io - make test-cci-export - comment-build-images: runs-on: ubuntu-latest needs: diff --git a/Makefile b/Makefile index 4271ae60..cd806cc7 100644 --- a/Makefile +++ b/Makefile @@ -43,18 +43,6 @@ stackrox-ui-test-image: -f images/stackrox-ui-test.Dockerfile \ images/ -.PHONY: test-cci-export -test-cci-export: - $(DOCKER) build \ - --platform linux/amd64 \ - -t test-cci-export \ - --build-arg BASE_TAG=$(STACKROX_TEST_TAG) \ - -f images/test.cci-export.Dockerfile \ - images/ - $(DOCKER) run \ - --rm \ - test-cci-export - .PHONY: scanner-build-image scanner-build-image: $(DOCKER) build \ diff --git a/images/jenkins-plugin.Dockerfile b/images/jenkins-plugin.Dockerfile index 852e4597..867115b5 100644 --- a/images/jenkins-plugin.Dockerfile +++ b/images/jenkins-plugin.Dockerfile @@ -24,11 +24,4 @@ RUN set -ex \ && sudo apt upgrade \ && sudo rm -rf /var/lib/apt/lists/* -COPY ./static-contents/bin/bash-wrapper /bin/ - -RUN \ - sudo mv /bin/bash /bin/real-bash && \ - sudo mv /bin/bash-wrapper /bin/bash && \ - sudo chmod 755 /bin/bash - USER circleci diff --git a/images/scanner-test.Dockerfile b/images/scanner-test.Dockerfile index 24ce54e8..fc0fa53d 100644 --- a/images/scanner-test.Dockerfile +++ b/images/scanner-test.Dockerfile @@ -26,10 +26,6 @@ RUN set -ex \ bash -c 'dir="$(dirname "${1}")"; new_dir="${dir#/static-tmp}"; mkdir -p "${new_dir}"; cp "${1}" "${new_dir}";' -- {} \ && rm -r /static-tmp -# Circle CI uses BASH_ENV to pass an environment for bash. Other environments need -# an initial BASH_ENV as a foundation for cci-export(). -ENV BASH_ENV /etc/initial-bash.env - # PostgreSQL environment. ENV PG_MAJOR=15 ENV PATH="$PATH:/usr/pgsql-$PG_MAJOR/bin/" @@ -120,7 +116,3 @@ RUN { \ echo "oc=$(oc version --client)"; \ echo "yq=$(yq --version)"; \ } > /i-am-rox-ci-image - -RUN \ - mv /bin/bash /bin/real-bash && \ - mv /bin/bash-wrapper /bin/bash diff --git a/images/stackrox-test.Dockerfile b/images/stackrox-test.Dockerfile index b7d9070c..86a9a454 100644 --- a/images/stackrox-test.Dockerfile +++ b/images/stackrox-test.Dockerfile @@ -23,9 +23,6 @@ RUN set -ex \ && find /static-tmp -type f -print0 | \ xargs -0 -I '{}' -n1 bash -c 'dir="$(dirname "${1}")"; new_dir="${dir#/static-tmp}"; mkdir -p "${new_dir}"; cp "${1}" "${new_dir}";' -- {} \ && rm -r /static-tmp -# Circle CI uses BASH_ENV to pass an environment for bash. Other environments need -# an initial BASH_ENV as a foundation for cci-export(). -ENV BASH_ENV /etc/initial-bash.env # Install Postgres repo RUN dnf --disablerepo="*" install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm @@ -186,7 +183,3 @@ RUN { \ echo "vault=$(vault --version)"; \ echo "yq=$(yq --version)"; \ } > /i-am-rox-ci-image - -RUN \ - mv /bin/bash /bin/real-bash && \ - mv /bin/bash-wrapper /bin/bash diff --git a/images/stackrox-ui-test.Dockerfile b/images/stackrox-ui-test.Dockerfile index 43e1f5c7..a70c91e4 100644 --- a/images/stackrox-ui-test.Dockerfile +++ b/images/stackrox-ui-test.Dockerfile @@ -23,9 +23,6 @@ RUN set -ex \ && find /static-tmp -type f -print0 | \ xargs -0 -I '{}' -n1 bash -c 'dir="$(dirname "${1}")"; new_dir="${dir#/static-tmp}"; mkdir -p "${new_dir}"; cp "${1}" "${new_dir}";' -- {} \ && rm -r /static-tmp -# Circle CI uses BASH_ENV to pass an environment for bash. Other environments need -# an initial BASH_ENV as a foundation for cci-export(). -ENV BASH_ENV /etc/initial-bash.env # Setup and install some prerequities RUN dnf update -y \ @@ -241,7 +238,3 @@ RUN { \ echo "yarn=$(yarn --version)"; \ echo "yq=$(yq --version)"; \ } > /i-am-rox-ci-image - -RUN \ - mv /bin/bash /bin/real-bash && \ - mv /bin/bash-wrapper /bin/bash diff --git a/images/static-contents/bin/bash-wrapper b/images/static-contents/bin/bash-wrapper deleted file mode 100755 index 1c19e3e7..00000000 --- a/images/static-contents/bin/bash-wrapper +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/real-bash -# shellcheck shell=bash - -# cci-export is a function which can be used to export environment variables in a way that is persistent -# across CircleCI steps. -cci-export() { - if [ "$#" -ne 2 ]; then - echo >&2 "Usage: $0 KEY VALUE" - return 1 - fi - - key="$1" - value="$2" - - export "${key}=${value}" - - if [[ "${CI:-false}" == "true" ]]; then - if [[ -z "${BASH_ENV:-}" ]]; then - echo >&2 "Env var BASH_ENV not properly set" - return 1 - fi - - # Use export with default value in the following form - # export __CCI_EXPORT_FOO_VALUE=bar - # export FOO="${FOO-"${__CCI_EXPORT_FOO_VALUE}"}"' - # for the following reasons: - # - Using Bash default value (FOO=${FOO-"${__CCI_EXPORT_FOO_VALUE}"}) - so that variables already set in the - # environment are not overwritten by `$BASH_ENV` (including variables set to empty string). - # - Using a variable holding the default value (__CCI_EXPORT_FOO_VALUE=value) - so that multiline values (e.g. - # certificates) are correctly escaped. - # - # An example of BASH_ENV contents: - # export __CCI_EXPORT_FOO_VALUE=bar - # export FOO="${FOO-"${__CCI_EXPORT_FOO_VALUE}"}"' - # export __CCI_EXPORT_BAZ_VALUE=baz - # export BAZ="${BAZ-"${__CCI_EXPORT_BAZ_VALUE}"}"' - - shadow_key="__CCI_EXPORT_${key}_VALUE" - - # Remove all lines starting with: - # export __CCI_EXPORT_VAR_VALUE= - # export VAR= - # for the same exported variable (VAR), to 'forget' about past cci-export calls, - # otherwise the first call to cci-export would define a default value for the variable, so that - # second and subsequent calls to cci-export would have no effect. - if [[ -f "$BASH_ENV" ]]; then - filtered_envfile="$(mktemp -t "bash.env-XXXX")" - # The first pattern (-e) is necessary for correctness - # The second pattern is optional for correctness, but it prevents duplicate lines cluttering the file - grep --invert-match --fixed-strings \ - -e "export ${shadow_key}=" \ - -e "export ${key}=" \ - "$BASH_ENV" > "${filtered_envfile}" && mv "${filtered_envfile}" "$BASH_ENV" - fi - - printf "export %s=%q\n" "$shadow_key" "$value" >> "$BASH_ENV" - # shellcheck disable=SC2016 # we must produce literal ${} symbols - printf 'export %s="${%s-"${%s}"}"\n' "$key" "$key" "$shadow_key" >> "$BASH_ENV" - fi -} - -export -f cci-export - -exec /bin/real-bash "$@" diff --git a/images/static-contents/etc/initial-bash.env b/images/static-contents/etc/initial-bash.env deleted file mode 100644 index a7992955..00000000 --- a/images/static-contents/etc/initial-bash.env +++ /dev/null @@ -1,2 +0,0 @@ -# Circle CI uses BASH_ENV to pass an environment for bash. Other environments need -# an initial BASH_ENV as a foundation for cci-export(). diff --git a/images/test.cci-export.Dockerfile b/images/test.cci-export.Dockerfile deleted file mode 100644 index 9b0c7fb5..00000000 --- a/images/test.cci-export.Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -ARG BASE_TAG -FROM quay.io/stackrox-io/apollo-ci:${BASE_TAG} - -COPY test/ . -ENV CI=true -ENV CIRCLECI=true - -CMD ["bats", "--print-output-on-failure", "--verbose-run", "bats/"] diff --git a/images/test/bats/cci-export.bats b/images/test/bats/cci-export.bats deleted file mode 100755 index 20a93956..00000000 --- a/images/test/bats/cci-export.bats +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env bats - -# To run the test locally do: -# make stackrox-build-image -# make stackrox-test-image -# make test-cci-export - -bats_helpers_root="/usr/lib/node_modules" -load "${bats_helpers_root}/bats-support/load.bash" -load "${bats_helpers_root}/bats-assert/load.bash" - -foo_printer() { - "bats/foo-printer.sh" "${@}" -} - -setup() { - export _CERT="bats/test-ca.crt" - export _FILE="bats/FILE" - # Create a file used in test-cases using subshell execution of 'cat' - echo "1.2.3" > "${_FILE}" - run test -f "${_FILE}" - assert_success - - bash_env="$(mktemp)" - export BASH_ENV="$bash_env" - # ensure clean start of every test case - unset FOO - echo "" > "$bash_env" - run echo $BASH_ENV - assert_output "$bash_env" - run cat $BASH_ENV - assert_output "" - run foo_printer - assert_output "FOO: " - run test -n $CIRCLECI - assert_success - run echo $CIRCLECI - assert_output "true" -} - -@test "cci-export BASH_ENV does not exist" { - run rm -f "${BASH_ENV}" - run test -f "${BASH_ENV}" - assert_failure - - run cci-export FOO cci1 - assert_success - run foo_printer - assert_output "FOO: cci1" - refute_output "FOO: " -} - -@test "cci-export sanity check single value" { - run cci-export FOO cci1 - assert_success - run foo_printer - assert_output "FOO: cci1" - refute_output "FOO: " - - run cci-export FOO cci2 - assert_success - run foo_printer - assert_output "FOO: cci2" - refute_output "FOO: cci1" -} - -@test "cci-export should escape special characters in values" { - run cci-export FOO 'quay.io/stackrox-"io"/super $canner:2.21.0-15-{{g44}(8f)2dc8fa}' - assert_success - run foo_printer - assert_output 'FOO: quay.io/stackrox-"io"/super $canner:2.21.0-15-{{g44}(8f)2dc8fa}' - refute_output "FOO: " -} - -@test "cci-export should properly handle multiline values" { - # Sanity check on cert test fixture - run test -f "${_CERT}" - assert_success - # The unprocessed cert should be parsable with openssl - run openssl x509 -in "${_CERT}" -noout - assert_success - - run cci-export CERT "$(cat ${_CERT})" - assert_success - - post_cert="${_CERT}.post" - foo_printer CERT --silent > "$post_cert" - # openssl should be able to load the cert after processing it with cci-export - run openssl x509 -in "$post_cert" -noout - assert_success - - run diff -q "${_CERT}" "$post_cert" - assert_success -} - -@test "cci-export should allow overwriting multiline values" { - run cci-export CERT "$(cat ${_CERT})" - assert_success - run foo_printer "CERT" - assert_line "CERT: -----BEGIN CERTIFICATE-----" - assert_line "-----END CERTIFICATE-----" - - run cci-export CERT "dummy" - run foo_printer "CERT" - assert_output "CERT: dummy" -} - -@test "cci-export should not leave duplicate lines in BASH_ENV" { - run cci-export FOO foo # creates 2 lines in BASH_ENV - run cci-export FOO foo2 # removes 2 and creates 2 lines in BASH_ENV - - run bash -c "grep FOO "$BASH_ENV" | wc -l" - assert_output 2 -} - -@test "cci-export sanity check many values" { - run cat "${_FILE}" - assert_output "1.2.3" - - export VAR=placeholder - run cci-export VAR1 "text/$VAR/text:$(cat "${_FILE}")" - run cci-export VAR2 "text/$VAR/text:$(cat "${_FILE}")" - run cci-export IMAGE3 "text/$VAR/text:$(cat "${_FILE}")" - - run foo_printer "VAR1" - assert_output "VAR1: text/$VAR/text:$(cat "${_FILE}")" - assert_output "VAR1: text/placeholder/text:1.2.3" - - run foo_printer VAR2 - assert_output "VAR2: text/$VAR/text:$(cat "${_FILE}")" - assert_output "VAR2: text/placeholder/text:1.2.3" - - run foo_printer IMAGE3 - assert_output "IMAGE3: text/$VAR/text:$(cat "${_FILE}")" - assert_output "IMAGE3: text/placeholder/text:1.2.3" -} - -@test "cci-export potentially colliding variable names" { - run cci-export PART1 "value1" - run cci-export PART1_PART2 "value_joined" - run cci-export PART1 "value2" - - run foo_printer PART1 - assert_output "PART1: value2" - refute_output "PART1: value1" - run foo_printer PART1_PART2 - assert_output "PART1_PART2: value_joined" -} - -@test "exported variable should be respected in a script" { - export FOO=bar - run foo_printer - assert_output "FOO: bar" - refute_output "FOO: " -} - -@test "shadowed variable should be respected in a script" { - FOO=bar run foo_printer - assert_output "FOO: bar" - refute_output "FOO: " -} - -@test "exported variable should have priority over the cci-exported one" { - run cci-export FOO cci - export FOO=bar - run foo_printer - assert_output "FOO: bar" - refute_output "FOO: cci" - refute_output "FOO: " -} - -@test "shadowed variable should have priority over the cci-exported one" { - run cci-export FOO cci - FOO=bar run foo_printer - assert_output "FOO: bar" - refute_output "FOO: cci" - refute_output "FOO: " -} - -@test "shadowed variable should have priority over both: the exported and the cci-exported one" { - export FOO=bar-export - run cci-export FOO cci - FOO=bar-shadow run foo_printer - assert_output "FOO: bar-shadow" - refute_output "FOO: bar-export" - refute_output "FOO: cci" - refute_output "FOO: " - - - run cci-export FOO cci2 - export FOO=bar-export2 - FOO=bar-shadow2 run foo_printer - assert_output "FOO: bar-shadow2" - refute_output "FOO: bar-export2" - refute_output "FOO: cci2" - refute_output "FOO: " -} - -@test "shadowed empty variable should be respected in a script" { - run cci-export FOO "value" - FOO="" run foo_printer - assert_output "FOO: " - refute_output "FOO: value" -} diff --git a/images/test/bats/foo-printer.sh b/images/test/bats/foo-printer.sh deleted file mode 100755 index cb09007a..00000000 --- a/images/test/bats/foo-printer.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -# prints the name (unless -s|--silent) and value of the variable given as parameter - -set -eo pipefail - -key="FOO" -value="$FOO" -sflag=0 - -while [[ "$#" -gt 0 ]]; do - case $1 in - -s|--silent) sflag=1 - ;; - *) key="$1"; value="${!1}" - ;; - esac - shift -done - -if (( sflag == 0 )); then - echo -n "$key: " -fi -echo "$value" diff --git a/images/test/bats/test-ca.crt b/images/test/bats/test-ca.crt deleted file mode 100644 index 73cbea3c..00000000 --- a/images/test/bats/test-ca.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC2jCCAkMCAg38MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG -A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE -MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl -YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw -ODIyMDUyNzQxWhcNMTcwODIxMDUyNzQxWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE -CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs -ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0z9FeMynsC8+u -dvX+LciZxnh5uRj4C9S6tNeeAlIGCfQYk0zUcNFCoCkTknNQd/YEiawDLNbxBqut -bMDZ1aarys1a0lYmUeVLCIqvzBkPJTSQsCopQQ9V8WuT252zzNzs68dVGNdCJd5J -NRQykpwexmnjPPv0mvj7i8XgG379TyW6P+WWV5okeUkXJ9eJS2ouDYdR2SM9BoVW -+FgxDu6BmXhozW5EfsnajFp7HL8kQClI0QOc79yuKl3492rH6bzFsFn2lfwWy9ic -7cP8EpCTeFp1tFaD+vxBhPZkeTQ1HKx6hQ5zeHIB5ySJJZ7af2W8r4eTGYzbdRW2 -4DDHCPhZAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAQMv+BFvGdMVzkQaQ3/+2noVz -/uAKbzpEL8xTcxYyP3lkOeh4FoxiSWqy5pGFALdPONoDuYFpLhjJSZaEwuvjI/Tr -rGhLV1pRG9frwDFshqD2Vaj4ENBCBh6UpeBop5+285zQ4SI7q4U9oSebUDJiuOx6 -+tZ9KynmrbJpTSi0+BM= ------END CERTIFICATE-----