From 9f58a6f17dca2cacda62db347d199ab5883148b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:23:22 +0000 Subject: [PATCH 01/21] Initial plan From f24ac33349de1d44ac1a1b5760c808958e09471d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:27:49 +0000 Subject: [PATCH 02/21] feat: add mirror overrides for feature download URLs Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/docker-in-docker/install.sh | 41 +++++++++++++---------- src/dotnet/scripts/dotnet-helpers.sh | 10 ++++-- src/github-cli/install.sh | 10 ++++-- src/go/install.sh | 12 ++++--- src/java/install.sh | 10 +++++- src/kubectl-helm-minikube/install.sh | 33 +++++++++++-------- src/node/install.sh | 6 ++-- src/nvidia-cuda/install.sh | 4 +-- src/php/install.sh | 9 +++-- src/powershell/install.sh | 49 ++++++---------------------- src/python/install.sh | 13 ++++++-- src/ruby/install.sh | 28 ++++++++++++++-- src/rust/install.sh | 5 +++ src/terraform/install.sh | 35 ++++++++++++-------- 14 files changed, 158 insertions(+), 107 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 5af320b0b..8e11755f2 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -19,6 +19,11 @@ INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"false"}" MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" MICROSOFT_GPG_KEYS_ROLLING_URI="https://packages.microsoft.com/keys/microsoft-rolling.asc" +MICROSOFT_PACKAGES_MIRROR="${MICROSOFT_PACKAGES_MIRROR:-https://packages.microsoft.com}" +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" +DOCKER_MIRROR="${DOCKER_MIRROR:-https://download.docker.com}" +MICROSOFT_GPG_KEYS_URI="${MICROSOFT_PACKAGES_MIRROR}/keys/microsoft.asc" +MICROSOFT_GPG_KEYS_ROLLING_URI="${MICROSOFT_PACKAGES_MIRROR}/keys/microsoft-rolling.asc" DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="trixie bookworm buster bullseye bionic focal jammy noble" DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="trixie bookworm buster bullseye bionic focal hirsute impish jammy noble" DISABLE_IP6_TABLES="${DISABLEIP6TABLES:-false}" @@ -329,7 +334,7 @@ if [ "${USE_MOBY}" = "true" ]; then curl -sSL ${MICROSOFT_GPG_KEYS_URI} curl -sSL ${MICROSOFT_GPG_KEYS_ROLLING_URI} } | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg - echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] ${MICROSOFT_PACKAGES_MIRROR}/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list ;; rhel) echo "(*) ${ID} detected - checking for Moby packages..." @@ -353,7 +358,7 @@ if [ "${USE_MOBY}" = "true" ]; then cat > /etc/yum.repos.d/microsoft.repo << EOF [microsoft] name=Microsoft Repository -baseurl=https://packages.microsoft.com/repos/microsoft-cbl-mariner-2.0-prod-base/ +baseurl=${MICROSOFT_PACKAGES_MIRROR}/repos/microsoft-cbl-mariner-2.0-prod-base/ enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/microsoft.gpg @@ -381,17 +386,17 @@ else cli_package_name="docker-ce-cli" case ${ADJUSTED_ID} in debian) - curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list + curl -fsSL ${DOCKER_MIRROR}/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] ${DOCKER_MIRROR}/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list ;; rhel) # Docker CE repository setup for RHEL-based systems setup_docker_ce_repo() { - curl -fsSL https://download.docker.com/linux/centos/gpg > /etc/pki/rpm-gpg/docker-ce.gpg + curl -fsSL ${DOCKER_MIRROR}/linux/centos/gpg > /etc/pki/rpm-gpg/docker-ce.gpg cat > /etc/yum.repos.d/docker-ce.repo << EOF [docker-ce-stable] name=Docker CE Stable -baseurl=https://download.docker.com/linux/centos/9/\$basearch/stable +baseurl=${DOCKER_MIRROR}/linux/centos/9/\$basearch/stable enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/docker-ce.gpg @@ -436,9 +441,9 @@ EOF *) # Standard RHEL/CentOS/Fedora approach if command -v dnf >/dev/null 2>&1; then - dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + dnf config-manager --add-repo ${DOCKER_MIRROR}/linux/centos/docker-ce.repo elif command -v yum-config-manager >/dev/null 2>&1; then - yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + yum-config-manager --add-repo ${DOCKER_MIRROR}/linux/centos/docker-ce.repo else # Manual fallback setup_docker_ce_repo @@ -608,7 +613,7 @@ else echo "(*) Downloading Docker CE packages manually..." # Get the repository baseurl - repo_baseurl="https://download.docker.com/linux/centos/9/x86_64/stable" + repo_baseurl="${DOCKER_MIRROR}/linux/centos/9/x86_64/stable" # Download packages directly cd /tmp/docker-ce-install @@ -685,7 +690,7 @@ fallback_compose(){ echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." get_previous_version "${url}" "${repo_url}" compose_version echo -e "\nAttempting to install v${compose_version}" - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} + curl -fsSL "${GITHUB_RELEASE_URL}/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} } # If 'docker-compose' command is to be included @@ -705,11 +710,11 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then if [ "${target_compose_arch}" = "x86_64" ]; then echo "(*) Installing docker compose v1..." - curl -fsSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} + curl -fsSL "${GITHUB_RELEASE_URL}/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} chmod +x ${docker_compose_path} # Download the SHA256 checksum - DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" + DOCKER_COMPOSE_SHA256="$(curl -sSL "${GITHUB_RELEASE_URL}/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum sha256sum -c docker-compose.sha256sum --ignore-missing elif [ "${VERSION_CODENAME}" = "bookworm" ]; then @@ -727,7 +732,7 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then docker_compose_url="https://github.com/docker/compose" find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" echo "(*) Installing docker-compose ${compose_version}..." - curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + curl -fsSL "${GITHUB_RELEASE_URL}/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." fallback_compose "$docker_compose_url" } @@ -735,7 +740,7 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then chmod +x ${docker_compose_path} # Download the SHA256 checksum - DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" + DOCKER_COMPOSE_SHA256="$(curl -sSL "${GITHUB_RELEASE_URL}/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum sha256sum -c docker-compose.sha256sum --ignore-missing @@ -751,7 +756,7 @@ fallback_compose-switch() { echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." get_previous_version "$url" "$repo_url" compose_switch_version echo -e "\nAttempting to install v${compose_switch_version}" - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${target_switch_arch}" -o /usr/local/bin/compose-switch + curl -fsSL "${GITHUB_RELEASE_URL}/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${target_switch_arch}" -o /usr/local/bin/compose-switch } # Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then @@ -776,7 +781,7 @@ if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /d arm64|aarch64) target_switch_arch=arm64 ;; *) target_switch_arch=${architecture} ;; esac - curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${target_switch_arch}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" + curl -fsSL "${GITHUB_RELEASE_URL}/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${target_switch_arch}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" chmod +x /usr/local/bin/compose-switch # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) @@ -811,7 +816,7 @@ fallback_buildx() { get_previous_version "$url" "$repo_url" buildx_version buildx_file_name="buildx-v${buildx_version}.linux-${target_buildx_arch}" echo -e "\nAttempting to install v${buildx_version}" - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} + wget ${GITHUB_RELEASE_URL}/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} } if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then @@ -830,7 +835,7 @@ if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then buildx_file_name="buildx-v${buildx_version}.linux-${target_buildx_arch}" cd /tmp - wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" + wget ${GITHUB_RELEASE_URL}/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" docker_home="/usr/libexec/docker" cli_plugins_dir="${docker_home}/cli-plugins" diff --git a/src/dotnet/scripts/dotnet-helpers.sh b/src/dotnet/scripts/dotnet-helpers.sh index e4c90819a..7a075edaa 100644 --- a/src/dotnet/scripts/dotnet-helpers.sh +++ b/src/dotnet/scripts/dotnet-helpers.sh @@ -8,7 +8,7 @@ # Maintainer: The Dev Container spec maintainers DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}") DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh" -DOTNET_RELEASES_INDEX_URL="https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json" +DOTNET_RELEASES_INDEX_URL="${DOTNET_RELEASES_MIRROR:-https://builds.dotnet.microsoft.com/dotnet}/release-metadata/releases-index.json" # Prints the latest active dotnet version from the releases index. # Usage: fetch_latest_version [] @@ -86,6 +86,9 @@ install_sdk() { fi local cmd=("$DOTNET_INSTALL_SCRIPT" "--version" "$version" "--install-dir" "$DOTNET_ROOT") + if [ -n "${DOTNET_RELEASES_MIRROR:-}" ]; then + cmd+=("--azure-feed" "${DOTNET_RELEASES_MIRROR}") + fi if [ -n "$channel" ]; then cmd+=("--channel" "$channel") fi @@ -125,6 +128,9 @@ install_runtime() { fi local cmd=("$DOTNET_INSTALL_SCRIPT" "--runtime" "$runtime" "--version" "$version" "--install-dir" "$DOTNET_ROOT" "--no-path") + if [ -n "${DOTNET_RELEASES_MIRROR:-}" ]; then + cmd+=("--azure-feed" "${DOTNET_RELEASES_MIRROR}") + fi if [ -n "$channel" ]; then cmd+=("--channel" "$channel") fi @@ -235,4 +241,4 @@ install_completions() { # Fish: drop into the standard vendor completions directory mkdir -p /usr/share/fish/vendor_completions.d "$DOTNET_ROOT/dotnet" completions script fish > /usr/share/fish/vendor_completions.d/dotnet.fish -} \ No newline at end of file +} diff --git a/src/github-cli/install.sh b/src/github-cli/install.sh index e3eaba0c3..225a51162 100755 --- a/src/github-cli/install.sh +++ b/src/github-cli/install.sh @@ -10,6 +10,7 @@ CLI_VERSION=${VERSION:-"latest"} INSTALL_DIRECTLY_FROM_GITHUB_RELEASE=${INSTALLDIRECTLYFROMGITHUBRELEASE:-"true"} EXTENSIONS=${EXTENSIONS:-""} +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" GITHUB_CLI_ARCHIVE_GPG_KEY=23F3D4EA75716059 @@ -25,6 +26,11 @@ fi # Get the list of GPG key servers that are reachable get_gpg_key_servers() { + if [ -n "${GPG_KEYSERVER:-}" ]; then + echo "keyserver ${GPG_KEYSERVER}" + return + fi + declare -A keyservers_curl_map=( ["hkp://keyserver.ubuntu.com"]="http://keyserver.ubuntu.com:11371" ["hkp://keyserver.ubuntu.com:80"]="http://keyserver.ubuntu.com" @@ -196,14 +202,14 @@ install_deb_using_github() { mkdir -p /tmp/ghcli pushd /tmp/ghcli - wget -q --show-progress --progress=dot:giga https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename} + wget -q --show-progress --progress=dot:giga ${GITHUB_RELEASE_URL}/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename} exit_code=$? set -e if [ "$exit_code" != "0" ]; then # Handle situation where git tags are ahead of what was is available to actually download echo "(!) github-cli version ${CLI_VERSION} failed to download. Attempting to fall back one version to retry..." find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli - wget -q --show-progress --progress=dot:giga https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename} + wget -q --show-progress --progress=dot:giga ${GITHUB_RELEASE_URL}/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename} fi dpkg -i /tmp/ghcli/${cli_filename} diff --git a/src/go/install.sh b/src/go/install.sh index 4286c08a8..21c8d0cd2 100755 --- a/src/go/install.sh +++ b/src/go/install.sh @@ -9,6 +9,8 @@ TARGET_GO_VERSION="${VERSION:-"latest"}" GOLANGCILINT_VERSION="${GOLANGCILINTVERSION:-"latest"}" +GO_MIRROR="${GO_MIRROR:-https://golang.org/dl}" +GO_TAG_SOURCE="${GO_TAG_SOURCE:-https://github.com/golang/go}" TARGET_GOROOT="${TARGET_GOROOT:-"/usr/local/go"}" TARGET_GOPATH="${TARGET_GOPATH:-"/go"}" @@ -220,7 +222,7 @@ if ! [ -f /usr/bin/find ]; then fi # Get closest match for version number specified -find_version_from_git_tags TARGET_GO_VERSION "https://go.googlesource.com/go" "tags/go" "." "true" +find_version_from_git_tags TARGET_GO_VERSION "${GO_TAG_SOURCE}" "tags/go" "." "true" architecture="$(uname -m)" case $architecture in @@ -248,7 +250,7 @@ if [[ "${TARGET_GO_VERSION}" != "none" ]] && [[ "$(go version 2>/dev/null)" != * gpg -q --import /tmp/tmp-gnupg/golang_key echo "Downloading Go ${TARGET_GO_VERSION}..." set +e - curl -fsSL -o /tmp/go.tar.gz "https://golang.org/dl/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz" + curl -fsSL -o /tmp/go.tar.gz "${GO_MIRROR}/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz" exit_code=$? set -e if [ "$exit_code" != "0" ]; then @@ -263,7 +265,7 @@ if [[ "${TARGET_GO_VERSION}" != "none" ]] && [[ "$(go version 2>/dev/null)" != * ((minor=minor-1)) TARGET_GO_VERSION="${major}.${minor}" # Look for latest version from previous minor release - find_version_from_git_tags TARGET_GO_VERSION "https://go.googlesource.com/go" "tags/go" "." "true" + find_version_from_git_tags TARGET_GO_VERSION "${GO_TAG_SOURCE}" "tags/go" "." "true" else ((breakfix=breakfix-1)) if [ "${breakfix}" = "0" ]; then @@ -274,9 +276,9 @@ if [[ "${TARGET_GO_VERSION}" != "none" ]] && [[ "$(go version 2>/dev/null)" != * fi set -e echo "Trying ${TARGET_GO_VERSION}..." - curl -fsSL -o /tmp/go.tar.gz "https://golang.org/dl/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz" + curl -fsSL -o /tmp/go.tar.gz "${GO_MIRROR}/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz" fi - curl -fsSL -o /tmp/go.tar.gz.asc "https://golang.org/dl/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz.asc" + curl -fsSL -o /tmp/go.tar.gz.asc "${GO_MIRROR}/go${TARGET_GO_VERSION}.linux-${architecture}.tar.gz.asc" gpg --verify /tmp/go.tar.gz.asc /tmp/go.tar.gz echo "Extracting Go ${TARGET_GO_VERSION}..." tar -xzf /tmp/go.tar.gz -C "${TARGET_GOROOT}" --strip-components=1 diff --git a/src/java/install.sh b/src/java/install.sh index 988460307..6b389a9c2 100644 --- a/src/java/install.sh +++ b/src/java/install.sh @@ -19,6 +19,7 @@ ANT_VERSION="${ANTVERSION:-"latest"}" INSTALL_GROOVY="${INSTALLGROOVY:-"false"}" GROOVY_VERSION="${GROOVYVERSION:-"latest"}" JDK_DISTRO="${JDKDISTRO:-"ms"}" +ADOPTIUM_API_URL="${ADOPTIUM_MIRROR:-https://api.adoptium.net}" export SDKMAN_DIR="${SDKMAN_DIR:-"/usr/local/sdkman"}" USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" @@ -204,7 +205,7 @@ find_version_list() { java_ver=$6 check_packages jq - all_versions=$(curl -s https://api.adoptium.net/v3/info/available_releases) + all_versions=$(curl -s "${ADOPTIUM_API_URL}/v3/info/available_releases") if [ "${ifLts}" = "true" ]; then major_version=$(echo "$all_versions" | jq -r '.most_recent_lts') elif [ "${java_ver}" = "latest" ]; then @@ -324,6 +325,13 @@ if [ ! -d "${SDKMAN_DIR}" ]; then export SDKMAN_NATIVE_VERSION="false" fi curl -sSL "https://get.sdkman.io?rcupdate=false" | bash + if [ -n "${SDKMAN_SERVICE_MIRROR:-}" ] && [ -f "${SDKMAN_DIR}/etc/config" ]; then + if grep -q "^sdkman_api=" "${SDKMAN_DIR}/etc/config"; then + sed -i "s|^sdkman_api=.*|sdkman_api=${SDKMAN_SERVICE_MIRROR}|" "${SDKMAN_DIR}/etc/config" + else + echo "sdkman_api=${SDKMAN_SERVICE_MIRROR}" >> "${SDKMAN_DIR}/etc/config" + fi + fi # For RHEL 8 systems, also disable native CLI in config file and remove native binaries if [ "${ADJUSTED_ID}" = "rhel" ] && [ "${MAJOR_VERSION_ID}" = "8" ]; then # Disable native CLI in config to prevent future usage diff --git a/src/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index 40901d3cb..bc5fd9ffd 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -18,6 +18,10 @@ KUBECTL_FALLBACK_VERSION="${KUBECTLFALLBACKVERSION:-"v1.35.1"}" KUBECTL_VERSION="${VERSION:-"latest"}" HELM_VERSION="${HELM:-"latest"}" MINIKUBE_VERSION="${MINIKUBE:-"latest"}" # latest is also valid +KUBECTL_MIRROR="${KUBECTL_MIRROR:-https://dl.k8s.io}" +HELM_MIRROR="${HELM_MIRROR:-https://get.helm.sh}" +MINIKUBE_MIRROR="${MINIKUBE_MIRROR:-https://storage.googleapis.com/minikube}" +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" KUBECTL_SHA256="${KUBECTL_SHA256:-"automatic"}" HELM_SHA256="${HELM_SHA256:-"automatic"}" @@ -167,13 +171,9 @@ if [ ${KUBECTL_VERSION} != "none" ]; then # Install the kubectl, verify checksum echo "Downloading kubectl..." if [ "${KUBECTL_VERSION}" = "latest" ] || [ "${KUBECTL_VERSION}" = "lts" ] || [ "${KUBECTL_VERSION}" = "current" ] || [ "${KUBECTL_VERSION}" = "stable" ]; then - KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 https://dl.k8s.io/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" + KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 ${KUBECTL_MIRROR}/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" if [ -z "${KUBECTL_VERSION}" ]; then - echo "(!) Failed to fetch kubectl stable version from dl.k8s.io, trying alternative URL..." - KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 https://storage.googleapis.com/kubernetes-release/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" - fi - if [ -z "${KUBECTL_VERSION}" ]; then - echo "(!) Failed to fetch kubectl stable version from both URLs. Using fallback version ${KUBECTL_FALLBACK_VERSION}" + echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}. Using fallback version ${KUBECTL_FALLBACK_VERSION}" KUBECTL_VERSION="${KUBECTL_FALLBACK_VERSION}" fi else @@ -182,10 +182,10 @@ if [ ${KUBECTL_VERSION} != "none" ]; then if [ "${KUBECTL_VERSION::1}" != 'v' ]; then KUBECTL_VERSION="v${KUBECTL_VERSION}" fi - curl -sSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" + curl -sSL -o /usr/local/bin/kubectl "${KUBECTL_MIRROR}/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" chmod 0755 /usr/local/bin/kubectl if [ "$KUBECTL_SHA256" = "automatic" ]; then - KUBECTL_SHA256="$(curl -sSL "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" + KUBECTL_SHA256="$(curl -sSL "${KUBECTL_MIRROR}/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" fi ([ "${KUBECTL_SHA256}" = "dev-mode" ] || (echo "${KUBECTL_SHA256} */usr/local/bin/kubectl" | sha256sum -c -)) if ! type kubectl > /dev/null 2>&1; then @@ -238,12 +238,17 @@ get_helm() { HELM_VERSION=$1 helm_filename="helm-${HELM_VERSION}-linux-${architecture}.tar.gz" tmp_helm_filename="/tmp/helm/${helm_filename}" - curl -sSL "https://get.helm.sh/${helm_filename}" -o "${tmp_helm_filename}" - curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.asc" -o "${tmp_helm_filename}.asc" + curl -sSL "${HELM_MIRROR}/${helm_filename}" -o "${tmp_helm_filename}" + curl -sSL "${GITHUB_RELEASE_URL}/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.asc" -o "${tmp_helm_filename}.asc" } # Get the list of GPG key servers that are reachable get_gpg_key_servers() { + if [ -n "${GPG_KEYSERVER:-}" ]; then + echo "keyserver ${GPG_KEYSERVER}" + return + fi + declare -A keyservers_curl_map=( ["hkp://keyserver.ubuntu.com"]="http://keyserver.ubuntu.com:11371" ["hkp://keyserver.ubuntu.com:80"]="http://keyserver.ubuntu.com" @@ -304,8 +309,8 @@ if [ ${HELM_VERSION} != "none" ]; then fi if [ "${HELM_SHA256}" = "automatic" ]; then - curl -sSL "https://get.helm.sh/${helm_filename}.sha256" -o "${tmp_helm_filename}.sha256" - curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.sha256.asc" -o "${tmp_helm_filename}.sha256.asc" + curl -sSL "${HELM_MIRROR}/${helm_filename}.sha256" -o "${tmp_helm_filename}.sha256" + curl -sSL "${GITHUB_RELEASE_URL}/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.sha256.asc" -o "${tmp_helm_filename}.sha256.asc" if ! gpg --verify "${tmp_helm_filename}.sha256.asc" > /tmp/helm/gnupg/verify.log 2>&1; then echo "Verification failed!" cat /tmp/helm/gnupg/verify.log @@ -347,10 +352,10 @@ if [ "${MINIKUBE_VERSION}" != "none" ]; then fi fi # latest is also valid in the download URLs - curl -sSL -o /usr/local/bin/minikube "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}" + curl -sSL -o /usr/local/bin/minikube "${MINIKUBE_MIRROR}/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}" chmod 0755 /usr/local/bin/minikube if [ "$MINIKUBE_SHA256" = "automatic" ]; then - MINIKUBE_SHA256="$(curl -sSL "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}.sha256")" + MINIKUBE_SHA256="$(curl -sSL "${MINIKUBE_MIRROR}/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}.sha256")" fi ([ "${MINIKUBE_SHA256}" = "dev-mode" ] || (echo "${MINIKUBE_SHA256} */usr/local/bin/minikube" | sha256sum -c -)) if ! type minikube > /dev/null 2>&1; then diff --git a/src/node/install.sh b/src/node/install.sh index 1d89abd0a..d25564413 100755 --- a/src/node/install.sh +++ b/src/node/install.sh @@ -11,6 +11,7 @@ export NODE_VERSION="${VERSION:-"lts"}" export PNPM_VERSION="${PNPMVERSION:-"latest"}" export NVM_VERSION="${NVMVERSION:-"latest"}" export NVM_DIR="${NVMINSTALLPATH:-"/usr/local/share/nvm"}" +export NVM_NODEJS_ORG_MIRROR="${NVM_NODEJS_ORG_MIRROR:-https://nodejs.org/dist}" INSTALL_TOOLS_FOR_NODE_GYP="${NODEGYPDEPENDENCIES:-true}" export INSTALL_YARN_USING_APT="${INSTALLYARNUSINGAPT:-false}" # only concerns Debian-based systems @@ -305,6 +306,7 @@ set -e umask 0002 # Do not update profile - we'll do this manually export PROFILE=/dev/null +export NVM_NODEJS_ORG_MIRROR="${NVM_NODEJS_ORG_MIRROR}" curl -so- "https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh" | bash || { PREV_NVM_VERSION=$(curl -s https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') curl -so- "https://raw.githubusercontent.com/nvm-sh/nvm/\${PREV_NVM_VERSION}/install.sh" | bash @@ -351,7 +353,7 @@ if [ ! -d "${NVM_DIR}" ]; then else echo "NVM already installed." if [ "${NODE_VERSION}" != "" ]; then - su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'" + su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR='${NVM_NODEJS_ORG_MIRROR}' && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'" fi fi @@ -369,7 +371,7 @@ if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then IFS="," read -a additional_versions <<< "$ADDITIONAL_VERSIONS" for ver in "${additional_versions[@]}"; do - su ${USERNAME} -c "umask 0002 && . '$NVM_DIR/nvm.sh' && nvm install '${ver}'" + su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR='${NVM_NODEJS_ORG_MIRROR}' && . '$NVM_DIR/nvm.sh' && nvm install '${ver}'" # possibly install yarn (puts yarn in per-Node install on RHEL, uses system yarn on Debian) install_yarn "${ver}" done diff --git a/src/nvidia-cuda/install.sh b/src/nvidia-cuda/install.sh index 66e4a6834..828cf868c 100644 --- a/src/nvidia-cuda/install.sh +++ b/src/nvidia-cuda/install.sh @@ -61,7 +61,7 @@ esac # Add NVIDIA's package repository to apt so that we can download packages # Updating the repo to ubuntu2204 as ubuntu 20.04 is going out of support. -NVIDIA_REPO_URL="https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/$NVIDIA_ARCH" +NVIDIA_REPO_URL="${NVIDIA_MIRROR:-https://developer.download.nvidia.com}/compute/cuda/repos/ubuntu2204/$NVIDIA_ARCH" if [ "${ID}" = "debian" ] && [ "${VERSION_CODENAME}" = "trixie" ]; then @@ -91,7 +91,7 @@ if ! apt-cache show "$cuda_pkg"; then echo "The requested version of CUDA is not available: CUDA $CUDA_VERSION" if [ "$NVIDIA_ARCH" = "arm64" ]; then echo "Note: arm64 supports limited CUDA versions. Please check available versions:" - echo "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/arm64" + echo "${NVIDIA_MIRROR:-https://developer.download.nvidia.com}/compute/cuda/repos/ubuntu2204/arm64" fi exit 1 fi diff --git a/src/php/install.sh b/src/php/install.sh index 357395e88..dd2bda965 100755 --- a/src/php/install.sh +++ b/src/php/install.sh @@ -14,6 +14,9 @@ rm -rf /var/lib/apt/lists/* PHP_VERSION="${VERSION:-"latest"}" INSTALL_COMPOSER="${INSTALLCOMPOSER:-"true"}" OVERRIDE_DEFAULT_VERSION="${OVERRIDEDEFAULTVERSION:-"true"}" +PHP_MIRROR="${PHP_MIRROR:-https://www.php.net/distributions}" +COMPOSER_MIRROR="${COMPOSER_MIRROR:-https://getcomposer.org}" +COMPOSER_SIG_MIRROR="${COMPOSER_SIG_MIRROR:-https://composer.github.io}" export PHP_DIR="${PHP_DIR:-"/usr/local/php"}" USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" @@ -163,8 +166,8 @@ find_prev_version_from_git_tags() { # Install PHP Composer addcomposer() { - "${PHP_SRC}" -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" - HASH="$(wget -q -O - https://composer.github.io/installer.sig)" + "${PHP_SRC}" -r "copy('${COMPOSER_MIRROR}/installer', 'composer-setup.php');" + HASH="$(wget -q -O - ${COMPOSER_SIG_MIRROR}/installer.sig)" "${PHP_SRC}" -r "if (hash_file('sha384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" "${PHP_SRC}" composer-setup.php --install-dir="/usr/local/bin" --filename=composer "${PHP_SRC}" -r "unlink('composer-setup.php');" @@ -181,7 +184,7 @@ init_php_install() { groupadd -r php fi usermod -a -G php "${USERNAME}" - PHP_URL="https://www.php.net/distributions/php-${PHP_VERSION}.tar.gz" + PHP_URL="${PHP_MIRROR}/php-${PHP_VERSION}.tar.gz" PHP_INI_DIR="${PHP_INSTALL_DIR}/ini" CONF_DIR="${PHP_INI_DIR}/conf.d" diff --git a/src/powershell/install.sh b/src/powershell/install.sh index cabd2cbb4..4e68e5854 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -15,8 +15,10 @@ rm -rf /var/lib/apt/lists/* POWERSHELL_VERSION=${VERSION:-"latest"} POWERSHELL_MODULES="${MODULES:-""}" POWERSHELL_PROFILE_URL="${POWERSHELLPROFILEURL}" +MICROSOFT_PACKAGES_MIRROR="${MICROSOFT_PACKAGES_MIRROR:-https://packages.microsoft.com}" +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" -MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +MICROSOFT_GPG_KEYS_URI="${MICROSOFT_PACKAGES_MIRROR}/keys/microsoft.asc" #MICROSOFT_GPG_KEYS_URI=$(curl https://packages.microsoft.com/keys/microsoft.asc -o /usr/share/keyrings/microsoft-archive-keyring.gpg) POWERSHELL_ARCHIVE_ARCHITECTURES_UBUNTU="amd64" POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX="x86_64" @@ -48,26 +50,6 @@ clean_cache() { rm -rf /var/cache/dnf/* fi } -# Function to resolve PowerShell version from Microsoft redirect URLs -resolve_powershell_version() { - local version_tag="$1" - local redirect_url="https://aka.ms/powershell-release?tag=${version_tag}" - - # Follow the redirect and extract the version from the final URL - local resolved_url - resolved_url=$(curl -sSL -o /dev/null -w '%{url_effective}' "${redirect_url}") - - # Extract version from URL (e.g., https://github.com/PowerShell/PowerShell/releases/tag/v7.4.7 -> 7.4.7) - local resolved_version - resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "") - - if [ -z "${resolved_version}" ]; then - echo "Failed to resolve version for tag: ${version_tag}" >&2 - return 1 - fi - - echo "${resolved_version}" -} # Install dependencies for RHEL/CentOS/AlmaLinux (DNF-based systems) install_using_dnf() { dnf remove -y curl-minimal @@ -83,14 +65,14 @@ install_powershell_dnf() { dnf install -y wget # Download Microsoft GPG key - curl https://packages.microsoft.com/keys/microsoft.asc -o /usr/share/keyrings/microsoft-archive-keyring.gpg + curl "${MICROSOFT_PACKAGES_MIRROR}/keys/microsoft.asc" -o /usr/share/keyrings/microsoft-archive-keyring.gpg ls -l /usr/share/keyrings/microsoft-archive-keyring.gpg # Install necessary dependencies dnf install -y krb5-libs libicu openssl-libs zlib # Add Microsoft PowerShell repository - curl "https://packages.microsoft.com/config/rhel/9.0/prod.repo" > /etc/yum.repos.d/microsoft.repo + curl "${MICROSOFT_PACKAGES_MIRROR}/config/rhel/9.0/prod.repo" > /etc/yum.repos.d/microsoft.repo # Install PowerShell dnf install --assumeyes powershell @@ -256,7 +238,7 @@ install_using_apt() { # Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] ${MICROSOFT_PACKAGES_MIRROR}/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list # Update lists @@ -365,7 +347,7 @@ install_pwsh() { powershell_target_path="/opt/microsoft/powershell/$(echo ${POWERSHELL_VERSION} | grep -oE '[^\.]+' | head -n 1)" mkdir -p /tmp/pwsh "${powershell_target_path}" cd /tmp/pwsh - curl -sSL -o "${powershell_filename}" "https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/${powershell_filename}" + curl -sSL -o "${powershell_filename}" "${GITHUB_RELEASE_URL}/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/${powershell_filename}" } install_using_github() { @@ -400,7 +382,7 @@ install_using_github() { fi # download the latest version of powershell and extracting the file to powershell directory - wget https://github.com/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/${powershell_filename} + wget ${GITHUB_RELEASE_URL}/PowerShell/PowerShell/releases/download/v${POWERSHELL_VERSION}/${powershell_filename} mkdir ~/powershell tar -xvf ${powershell_filename} -C ~/powershell @@ -430,18 +412,7 @@ install_using_github() { if ! type pwsh >/dev/null 2>&1; then export DEBIAN_FRONTEND=noninteractive - if [ "${POWERSHELL_VERSION}" = "lts" ] || [ "${POWERSHELL_VERSION}" = "stable" ] || [ "${POWERSHELL_VERSION}" = "preview" ]; then - echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from Microsoft..." - resolved_version=$(resolve_powershell_version "${POWERSHELL_VERSION}") - if [ -n "${resolved_version}" ]; then - echo "Resolved '${POWERSHELL_VERSION}' to version: ${resolved_version}" - POWERSHELL_VERSION="${resolved_version}" - else - echo "Warning: Could not resolve '${POWERSHELL_VERSION}' version. Falling back to 'latest'." - POWERSHELL_VERSION="latest" - fi - fi - + # Source /etc/os-release to get OS info . /etc/os-release architecture="$(uname -m)" @@ -500,4 +471,4 @@ fi # Clean up rm -rf /var/lib/apt/lists/* -echo "Done!" \ No newline at end of file +echo "Done!" diff --git a/src/python/install.sh b/src/python/install.sh index be895927d..aa0bcf2ef 100755 --- a/src/python/install.sh +++ b/src/python/install.sh @@ -14,6 +14,8 @@ OPTIMIZE_BUILD_FROM_SOURCE="${OPTIMIZE:-"false"}" ENABLE_SHARED_FROM_SOURCE="${ENABLESHARED:-"false"}" PYTHON_INSTALL_PATH="${INSTALLPATH:-"/usr/local/python"}" OVERRIDE_DEFAULT_VERSION="${OVERRIDEDEFAULTVERSION:-"true"}" +PYTHON_MIRROR="${PYTHON_MIRROR:-https://www.python.org/ftp}" +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" export PIPX_HOME=${PIPX_HOME:-"/usr/local/py-utils"} @@ -156,6 +158,11 @@ updaterc() { # Get the list of GPG key servers that are reachable get_gpg_key_servers() { + if [ -n "${GPG_KEYSERVER:-}" ]; then + echo "keyserver ${GPG_KEYSERVER}" + return + fi + declare -A keyservers_curl_map=( ["hkp://keyserver.ubuntu.com"]="http://keyserver.ubuntu.com:11371" ["hkp://keyserver.ubuntu.com:80"]="http://keyserver.ubuntu.com" @@ -494,7 +501,7 @@ install_cpython() { mkdir -p /tmp/python-src ${INSTALL_PATH} cd /tmp/python-src cpython_tgz_filename="Python-${VERSION}.tgz" - cpython_tgz_url="https://www.python.org/ftp/python/${VERSION}/${cpython_tgz_filename}" + cpython_tgz_url="${PYTHON_MIRROR}/python/${VERSION}/${cpython_tgz_filename}" echo "Downloading ${cpython_tgz_filename}..." curl -sSL -o "/tmp/python-src/${cpython_tgz_filename}" "${cpython_tgz_url}" fi @@ -525,7 +532,7 @@ install_cosign() { local version_for_url="${COSIGN_VERSION#v}" local cosign_filename="/tmp/cosign_${version_for_url}_${architecture}.deb" - local cosign_url="https://github.com/sigstore/cosign/releases/download/v${version_for_url}/cosign_${version_for_url}_${architecture}.deb" + local cosign_url="${GITHUB_RELEASE_URL}/sigstore/cosign/releases/download/v${version_for_url}/cosign_${version_for_url}_${architecture}.deb" echo "Downloading cosign from: ${cosign_url}" @@ -539,7 +546,7 @@ install_cosign() { version_for_url="${COSIGN_VERSION#v}" cosign_filename="/tmp/cosign_${version_for_url}_${architecture}.deb" - cosign_url="https://github.com/sigstore/cosign/releases/download/v${version_for_url}/cosign_${version_for_url}_${architecture}.deb" + cosign_url="${GITHUB_RELEASE_URL}/sigstore/cosign/releases/download/v${version_for_url}/cosign_${version_for_url}_${architecture}.deb" if ! curl -L -f --fail-with-body "${cosign_url}" -o "$cosign_filename" 2>/dev/null; then echo "(!) Failed to download cosign v${COSIGN_VERSION} as fallback" diff --git a/src/ruby/install.sh b/src/ruby/install.sh index 39cb5be03..d8fcf3e68 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -70,6 +70,11 @@ updaterc() { # Get the list of GPG key servers that are reachable get_gpg_key_servers() { + if [ -n "${GPG_KEYSERVER:-}" ]; then + echo "keyserver ${GPG_KEYSERVER}" + return + fi + declare -A keyservers_curl_map=( ["hkp://keyserver.ubuntu.com"]="http://keyserver.ubuntu.com:11371" ["hkp://keyserver.ubuntu.com:80"]="http://keyserver.ubuntu.com" @@ -323,12 +328,25 @@ set_rvm_install_args() { fi } +run_rvm_installer() { + local install_args="$1" + if [ -n "${RVM_INSTALL_MIRROR:-}" ]; then + local rvm_tmp_dir + rvm_tmp_dir="$(mktemp -d)" + git clone --depth=1 "${RVM_INSTALL_MIRROR}/rvm/rvm.git" "${rvm_tmp_dir}/rvm" + "${rvm_tmp_dir}/rvm/binscripts/rvm-installer" stable --ignore-dotfiles ${install_args} --with-default-gems="${DEFAULT_GEMS}" 2>&1 + rm -rf "${rvm_tmp_dir}" + else + curl -sSL https://get.rvm.io | bash -s stable --ignore-dotfiles ${install_args} --with-default-gems="${DEFAULT_GEMS}" 2>&1 + fi +} + install_previous_version() { if [[ $ORIGINAL_RUBY_VERSION == "latest" ]]; then repo_url=$(get_github_api_repo_url "$RUBY_URL") get_previous_version "${RUBY_URL}" "${repo_url}" RUBY_VERSION set_rvm_install_args $RUBY_VERSION - curl -sSL https://get.rvm.io | bash -s stable --ignore-dotfiles ${RVM_INSTALL_ARGS} --with-default-gems="${DEFAULT_GEMS}" 2>&1 + run_rvm_installer "${RVM_INSTALL_ARGS}" else echo "Failed to install Ruby version $ORIGINAL_RUBY_VERSION. Exiting..." fi @@ -354,8 +372,14 @@ else if ! cat /etc/group | grep -e "^rvm:" > /dev/null 2>&1; then groupadd -r rvm fi + if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -q "^rvm_rubies_url=${RUBY_SOURCE_MIRROR}$" /etc/rvmrc 2>/dev/null; then + echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc + fi + if [ -n "${RUBY_BINARIES_MIRROR:-}" ] && ! grep -q "^rvm_binaries_url=${RUBY_BINARIES_MIRROR}$" /etc/rvmrc 2>/dev/null; then + echo "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" >> /etc/rvmrc + fi # Install rvm - curl -sSL https://get.rvm.io | bash -s stable --ignore-dotfiles ${RVM_INSTALL_ARGS} --with-default-gems="${DEFAULT_GEMS}" 2>&1 || install_previous_version + run_rvm_installer "${RVM_INSTALL_ARGS}" || install_previous_version usermod -aG rvm ${USERNAME} source /usr/local/rvm/scripts/rvm rvm fix-permissions system diff --git a/src/rust/install.sh b/src/rust/install.sh index 99a7ba8f5..f7b98341d 100755 --- a/src/rust/install.sh +++ b/src/rust/install.sh @@ -390,6 +390,9 @@ else rm -rf /tmp/rustup fi +export RUSTUP_DIST_SERVER="${RUSTUP_DIST_SERVER:-https://static.rust-lang.org}" +export RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}" + export PATH=${CARGO_HOME}/bin:${PATH} if [ "${UPDATE_RUST}" = "true" ]; then echo "Updating Rust..." @@ -421,6 +424,8 @@ fi updaterc "$(cat << EOF export RUSTUP_HOME="${RUSTUP_HOME}" export CARGO_HOME="${CARGO_HOME}" +export RUSTUP_DIST_SERVER="${RUSTUP_DIST_SERVER}" +export RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT}" if [[ "\${PATH}" != *"\${CARGO_HOME}/bin"* ]]; then export PATH="\${CARGO_HOME}/bin:\${PATH}"; fi EOF )" diff --git a/src/terraform/install.sh b/src/terraform/install.sh index 999815a38..53f9f21b0 100755 --- a/src/terraform/install.sh +++ b/src/terraform/install.sh @@ -28,6 +28,7 @@ TERRAGRUNT_SHA256="${TERRAGRUNT_SHA256:-"automatic"}" SENTINEL_SHA256="${SENTINEL_SHA256:-"automatic"}" TFSEC_SHA256="${TFSEC_SHA256:-"automatic"}" TERRAFORM_DOCS_SHA256="${TERRAFORM_DOCS_SHA256:-"automatic"}" +GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" HASHICORP_RELEASES_URL="https://releases.hashicorp.com" if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then @@ -36,6 +37,7 @@ fi TERRAFORM_GPG_KEY="72D7468F" TFLINT_GPG_KEY_URI="https://raw.githubusercontent.com/terraform-linters/tflint/v0.46.1/8CE69160EB3F2FE9.key" +HASHICORP_KEY_URL="${HASHICORP_GPG_KEY_MIRROR:-https://keybase.io}/hashicorp/pgp_keys.asc" KEYSERVER_PROXY="${HTTPPROXY:-"${HTTP_PROXY:-""}"}" architecture="$(uname -m)" @@ -61,6 +63,11 @@ fi # Get the list of GPG key servers that are reachable get_gpg_key_servers() { + if [ -n "${GPG_KEYSERVER:-}" ]; then + echo "keyserver ${GPG_KEYSERVER}" + return + fi + declare -A keyservers_curl_map=( ["hkps://keyserver.ubuntu.com"]="https://keyserver.ubuntu.com" ["hkps://keys.openpgp.org"]="https://keys.openpgp.org" @@ -114,7 +121,7 @@ receive_gpg_keys() { # Special handling for HashiCorp GPG key on Ubuntu Noble if [ "$IS_GPG_NEW" -eq 1 ] && [ "$keys" = "$TERRAFORM_GPG_KEY" ]; then echo "(*) Ubuntu Noble detected, using Keybase for HashiCorp GPG key import...." - curl -fsSL https://keybase.io/hashicorp/pgp_keys.asc | gpg --import + curl -fsSL "${HASHICORP_KEY_URL}" | gpg --import if ! gpg --list-keys "${TERRAFORM_GPG_KEY}" > /dev/null 2>&1; then gpg --list-keys echo "(*) Warning: HashiCorp GPG key not found in keyring after import." @@ -332,7 +339,7 @@ install_cosign() { COSIGN_VERSION=$1 local URL=$2 cosign_filename="/tmp/cosign_${COSIGN_VERSION}_${architecture}.deb" - cosign_url="https://github.com/sigstore/cosign/releases/latest/download/cosign_${COSIGN_VERSION}_${architecture}.deb" + cosign_url="${GITHUB_RELEASE_URL}/sigstore/cosign/releases/latest/download/cosign_${COSIGN_VERSION}_${architecture}.deb" curl -L "${cosign_url}" -o $cosign_filename if grep -q "Not Found" "$cosign_filename"; then echo -e "\n(!) Failed to fetch the latest artifacts for cosign v${COSIGN_VERSION}..." @@ -340,7 +347,7 @@ install_cosign() { get_previous_version "$URL" "$REPO_URL" COSIGN_VERSION echo -e "\nAttempting to install ${COSIGN_VERSION}" cosign_filename="/tmp/cosign_${COSIGN_VERSION}_${architecture}.deb" - cosign_url="https://github.com/sigstore/cosign/releases/latest/download/cosign_${COSIGN_VERSION}_${architecture}.deb" + cosign_url="${GITHUB_RELEASE_URL}/sigstore/cosign/releases/latest/download/cosign_${COSIGN_VERSION}_${architecture}.deb" curl -L "${cosign_url}" -o $cosign_filename fi dpkg -i $cosign_filename @@ -457,7 +464,7 @@ mv -f terraform /usr/local/bin/ install_tflint() { TFLINT_VERSION=$1 - curl -sSL -o /tmp/tf-downloads/${TFLINT_FILENAME} https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/${TFLINT_FILENAME} + curl -sSL -o /tmp/tf-downloads/${TFLINT_FILENAME} ${GITHUB_RELEASE_URL}/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/${TFLINT_FILENAME} } if [ "${TFLINT_VERSION}" != "none" ]; then @@ -473,16 +480,16 @@ if [ "${TFLINT_VERSION}" != "none" ]; then echo "${TFLINT_SHA256} *${TFLINT_FILENAME}" > tflint_checksums.txt sha256sum --ignore-missing -c tflint_checksums.txt else - curl -sSL -o tflint_checksums.txt https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt + curl -sSL -o tflint_checksums.txt ${GITHUB_RELEASE_URL}/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt set +e - curl -sSL -o checksums.txt.keyless.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig + curl -sSL -o checksums.txt.keyless.sig ${GITHUB_RELEASE_URL}/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.keyless.sig set -e # Check that checksums.txt.keyless.sig exists and is not empty if [ -s checksums.txt.keyless.sig ]; then # Validate checksums with cosign - curl -sSL -o checksums.txt.pem https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem + curl -sSL -o checksums.txt.pem ${GITHUB_RELEASE_URL}/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.pem ensure_cosign cosign verify-blob \ --certificate=/tmp/tf-downloads/checksums.txt.pem \ @@ -496,7 +503,7 @@ if [ "${TFLINT_VERSION}" != "none" ]; then sha256sum --ignore-missing -c tflint_checksums.txt else # Fallback to older, GPG-based verification (pre-0.47.0 of tflint) - curl -sSL -o tflint_checksums.txt.sig https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig + curl -sSL -o tflint_checksums.txt.sig ${GITHUB_RELEASE_URL}/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/checksums.txt.sig curl -sSL -o tflint_key "${TFLINT_GPG_KEY_URI}" gpg -q --import tflint_key gpg --verify tflint_checksums.txt.sig tflint_checksums.txt @@ -510,7 +517,7 @@ fi install_terragrunt() { TERRAGRUNT_VERSION=$1 - curl -sSL -o /tmp/tf-downloads/${terragrunt_filename} https://github.com/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/${terragrunt_filename} + curl -sSL -o /tmp/tf-downloads/${terragrunt_filename} ${GITHUB_RELEASE_URL}/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/${terragrunt_filename} } if [ "${TERRAGRUNT_VERSION}" != "none" ]; then @@ -523,7 +530,7 @@ if [ "${TERRAGRUNT_VERSION}" != "none" ]; then fi if [ "${TERRAGRUNT_SHA256}" != "dev-mode" ]; then if [ "${TERRAGRUNT_SHA256}" = "automatic" ]; then - curl -sSL -o terragrunt_SHA256SUMS https://github.com/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/SHA256SUMS + curl -sSL -o terragrunt_SHA256SUMS ${GITHUB_RELEASE_URL}/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/SHA256SUMS else echo "${TERRAGRUNT_SHA256} *${terragrunt_filename}" > terragrunt_SHA256SUMS fi @@ -576,7 +583,7 @@ fi install_tfsec() { local TFSEC_VERSION=$1 tfsec_filename="tfsec_${TFSEC_VERSION}_linux_${architecture}.tar.gz" - curl -sSL -o /tmp/tf-downloads/${tfsec_filename} https://github.com/aquasecurity/tfsec/releases/download/v${TFSEC_VERSION}/${tfsec_filename} + curl -sSL -o /tmp/tf-downloads/${tfsec_filename} ${GITHUB_RELEASE_URL}/aquasecurity/tfsec/releases/download/v${TFSEC_VERSION}/${tfsec_filename} } if [ "${INSTALL_TFSEC}" = "true" ]; then @@ -592,7 +599,7 @@ if [ "${INSTALL_TFSEC}" = "true" ]; then fi if [ "${TFSEC_SHA256}" != "dev-mode" ]; then if [ "${TFSEC_SHA256}" = "automatic" ]; then - curl -sSL -o tfsec_SHA256SUMS https://github.com/aquasecurity/tfsec/releases/download/v${TFSEC_VERSION}/tfsec_${TFSEC_VERSION}_checksums.txt + curl -sSL -o tfsec_SHA256SUMS ${GITHUB_RELEASE_URL}/aquasecurity/tfsec/releases/download/v${TFSEC_VERSION}/tfsec_${TFSEC_VERSION}_checksums.txt else echo "${TFSEC_SHA256} *${tfsec_filename}" > tfsec_SHA256SUMS fi @@ -607,7 +614,7 @@ fi install_terraform_docs() { local TERRAFORM_DOCS_VERSION=$1 tfdocs_filename="terraform-docs-v${TERRAFORM_DOCS_VERSION}-linux-${architecture}.tar.gz" - curl -sSL -o /tmp/tf-downloads/${tfdocs_filename} https://github.com/terraform-docs/terraform-docs/releases/download/v${TERRAFORM_DOCS_VERSION}/${tfdocs_filename} + curl -sSL -o /tmp/tf-downloads/${tfdocs_filename} ${GITHUB_RELEASE_URL}/terraform-docs/terraform-docs/releases/download/v${TERRAFORM_DOCS_VERSION}/${tfdocs_filename} } if [ "${INSTALL_TERRAFORM_DOCS}" = "true" ]; then @@ -623,7 +630,7 @@ if [ "${INSTALL_TERRAFORM_DOCS}" = "true" ]; then fi if [ "${TERRAFORM_DOCS_SHA256}" != "dev-mode" ]; then if [ "${TERRAFORM_DOCS_SHA256}" = "automatic" ]; then - curl -sSL -o tfdocs_SHA256SUMS https://github.com/terraform-docs/terraform-docs/releases/download/v${TERRAFORM_DOCS_VERSION}/terraform-docs-v${TERRAFORM_DOCS_VERSION}.sha256sum + curl -sSL -o tfdocs_SHA256SUMS ${GITHUB_RELEASE_URL}/terraform-docs/terraform-docs/releases/download/v${TERRAFORM_DOCS_VERSION}/terraform-docs-v${TERRAFORM_DOCS_VERSION}.sha256sum else echo "${TERRAFORM_DOCS_SHA256} *${tfsec_filename}" > tfdocs_SHA256SUMS fi From c2be3b67b6bd95a3d839bbd3f7a6323f95ba319b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:28:26 +0000 Subject: [PATCH 03/21] chore: clean docker mirror variable initialization Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/docker-in-docker/install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 8e11755f2..bb1d264e3 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -17,8 +17,6 @@ DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL:-""}" USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"false"}" -MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" -MICROSOFT_GPG_KEYS_ROLLING_URI="https://packages.microsoft.com/keys/microsoft-rolling.asc" MICROSOFT_PACKAGES_MIRROR="${MICROSOFT_PACKAGES_MIRROR:-https://packages.microsoft.com}" GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" DOCKER_MIRROR="${DOCKER_MIRROR:-https://download.docker.com}" From b0a6037f014fd956d31aae86dde64bd88dbd8e1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:29:18 +0000 Subject: [PATCH 04/21] fix: harden mirror string handling in ruby and java scripts Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/java/install.sh | 3 ++- src/ruby/install.sh | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java/install.sh b/src/java/install.sh index 6b389a9c2..5bd7bd028 100644 --- a/src/java/install.sh +++ b/src/java/install.sh @@ -326,8 +326,9 @@ if [ ! -d "${SDKMAN_DIR}" ]; then fi curl -sSL "https://get.sdkman.io?rcupdate=false" | bash if [ -n "${SDKMAN_SERVICE_MIRROR:-}" ] && [ -f "${SDKMAN_DIR}/etc/config" ]; then + sdkman_service_mirror_escaped="$(printf '%s\n' "${SDKMAN_SERVICE_MIRROR}" | sed 's/[&|\\]/\\&/g')" if grep -q "^sdkman_api=" "${SDKMAN_DIR}/etc/config"; then - sed -i "s|^sdkman_api=.*|sdkman_api=${SDKMAN_SERVICE_MIRROR}|" "${SDKMAN_DIR}/etc/config" + sed -i "s|^sdkman_api=.*|sdkman_api=${sdkman_service_mirror_escaped}|" "${SDKMAN_DIR}/etc/config" else echo "sdkman_api=${SDKMAN_SERVICE_MIRROR}" >> "${SDKMAN_DIR}/etc/config" fi diff --git a/src/ruby/install.sh b/src/ruby/install.sh index d8fcf3e68..d37eeea12 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -372,10 +372,10 @@ else if ! cat /etc/group | grep -e "^rvm:" > /dev/null 2>&1; then groupadd -r rvm fi - if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -q "^rvm_rubies_url=${RUBY_SOURCE_MIRROR}$" /etc/rvmrc 2>/dev/null; then + if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -Fqx "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" /etc/rvmrc 2>/dev/null; then echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc fi - if [ -n "${RUBY_BINARIES_MIRROR:-}" ] && ! grep -q "^rvm_binaries_url=${RUBY_BINARIES_MIRROR}$" /etc/rvmrc 2>/dev/null; then + if [ -n "${RUBY_BINARIES_MIRROR:-}" ] && ! grep -Fqx "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" /etc/rvmrc 2>/dev/null; then echo "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" >> /etc/rvmrc fi # Install rvm From 151d0a65a097273e802523e950c340b5b6d28c73 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:30:26 +0000 Subject: [PATCH 05/21] fix: address validation feedback in kubectl node ruby Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/kubectl-helm-minikube/install.sh | 4 ++-- src/node/install.sh | 5 +++-- src/ruby/install.sh | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index bc5fd9ffd..82a47afe5 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -171,7 +171,7 @@ if [ ${KUBECTL_VERSION} != "none" ]; then # Install the kubectl, verify checksum echo "Downloading kubectl..." if [ "${KUBECTL_VERSION}" = "latest" ] || [ "${KUBECTL_VERSION}" = "lts" ] || [ "${KUBECTL_VERSION}" = "current" ] || [ "${KUBECTL_VERSION}" = "stable" ]; then - KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 ${KUBECTL_MIRROR}/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" + KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 "${KUBECTL_MIRROR}/release/stable.txt" 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" if [ -z "${KUBECTL_VERSION}" ]; then echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}. Using fallback version ${KUBECTL_FALLBACK_VERSION}" KUBECTL_VERSION="${KUBECTL_FALLBACK_VERSION}" @@ -185,7 +185,7 @@ if [ ${KUBECTL_VERSION} != "none" ]; then curl -sSL -o /usr/local/bin/kubectl "${KUBECTL_MIRROR}/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" chmod 0755 /usr/local/bin/kubectl if [ "$KUBECTL_SHA256" = "automatic" ]; then - KUBECTL_SHA256="$(curl -sSL "${KUBECTL_MIRROR}/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" + KUBECTL_SHA256="$(curl -sSL "${KUBECTL_MIRROR}/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" fi ([ "${KUBECTL_SHA256}" = "dev-mode" ] || (echo "${KUBECTL_SHA256} */usr/local/bin/kubectl" | sha256sum -c -)) if ! type kubectl > /dev/null 2>&1; then diff --git a/src/node/install.sh b/src/node/install.sh index d25564413..b624aede2 100755 --- a/src/node/install.sh +++ b/src/node/install.sh @@ -12,6 +12,7 @@ export PNPM_VERSION="${PNPMVERSION:-"latest"}" export NVM_VERSION="${NVMVERSION:-"latest"}" export NVM_DIR="${NVMINSTALLPATH:-"/usr/local/share/nvm"}" export NVM_NODEJS_ORG_MIRROR="${NVM_NODEJS_ORG_MIRROR:-https://nodejs.org/dist}" +NVM_NODEJS_ORG_MIRROR_ESCAPED="$(printf '%q' "${NVM_NODEJS_ORG_MIRROR}")" INSTALL_TOOLS_FOR_NODE_GYP="${NODEGYPDEPENDENCIES:-true}" export INSTALL_YARN_USING_APT="${INSTALLYARNUSINGAPT:-false}" # only concerns Debian-based systems @@ -353,7 +354,7 @@ if [ ! -d "${NVM_DIR}" ]; then else echo "NVM already installed." if [ "${NODE_VERSION}" != "" ]; then - su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR='${NVM_NODEJS_ORG_MIRROR}' && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'" + su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR_ESCAPED} && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'" fi fi @@ -371,7 +372,7 @@ if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then IFS="," read -a additional_versions <<< "$ADDITIONAL_VERSIONS" for ver in "${additional_versions[@]}"; do - su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR='${NVM_NODEJS_ORG_MIRROR}' && . '$NVM_DIR/nvm.sh' && nvm install '${ver}'" + su ${USERNAME} -c "umask 0002 && export NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR_ESCAPED} && . '$NVM_DIR/nvm.sh' && nvm install '${ver}'" # possibly install yarn (puts yarn in per-Node install on RHEL, uses system yarn on Debian) install_yarn "${ver}" done diff --git a/src/ruby/install.sh b/src/ruby/install.sh index d37eeea12..bfb0f7136 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -372,6 +372,10 @@ else if ! cat /etc/group | grep -e "^rvm:" > /dev/null 2>&1; then groupadd -r rvm fi + if [[ "${RUBY_SOURCE_MIRROR:-}" == *$'\n'* ]] || [[ "${RUBY_BINARIES_MIRROR:-}" == *$'\n'* ]]; then + echo "(!) Mirror values must not contain newlines." + exit 1 + fi if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -Fqx "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" /etc/rvmrc 2>/dev/null; then echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc fi From 7b5c864597fbba2e4ab67cef54282a7d8b3794cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:31:27 +0000 Subject: [PATCH 06/21] fix: harden sdkman and ruby mirror config writes Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/java/install.sh | 15 +++++++++------ src/ruby/install.sh | 11 +++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/java/install.sh b/src/java/install.sh index 5bd7bd028..c3ab5f406 100644 --- a/src/java/install.sh +++ b/src/java/install.sh @@ -326,12 +326,15 @@ if [ ! -d "${SDKMAN_DIR}" ]; then fi curl -sSL "https://get.sdkman.io?rcupdate=false" | bash if [ -n "${SDKMAN_SERVICE_MIRROR:-}" ] && [ -f "${SDKMAN_DIR}/etc/config" ]; then - sdkman_service_mirror_escaped="$(printf '%s\n' "${SDKMAN_SERVICE_MIRROR}" | sed 's/[&|\\]/\\&/g')" - if grep -q "^sdkman_api=" "${SDKMAN_DIR}/etc/config"; then - sed -i "s|^sdkman_api=.*|sdkman_api=${sdkman_service_mirror_escaped}|" "${SDKMAN_DIR}/etc/config" - else - echo "sdkman_api=${SDKMAN_SERVICE_MIRROR}" >> "${SDKMAN_DIR}/etc/config" - fi + sdkman_config_tmp="$(mktemp)" + awk -v api="${SDKMAN_SERVICE_MIRROR}" ' + BEGIN { updated=0 } + /^sdkman_api=/ { print "sdkman_api=" api; updated=1; next } + { print } + END { if (updated == 0) print "sdkman_api=" api } + ' "${SDKMAN_DIR}/etc/config" > "${sdkman_config_tmp}" + cat "${sdkman_config_tmp}" > "${SDKMAN_DIR}/etc/config" + rm -f "${sdkman_config_tmp}" fi # For RHEL 8 systems, also disable native CLI in config file and remove native binaries if [ "${ADJUSTED_ID}" = "rhel" ] && [ "${MAJOR_VERSION_ID}" = "8" ]; then diff --git a/src/ruby/install.sh b/src/ruby/install.sh index bfb0f7136..aeedafb8f 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -328,6 +328,15 @@ set_rvm_install_args() { fi } +validate_mirror_url() { + local mirror_name="$1" + local mirror_url="$2" + if [ -n "${mirror_url}" ] && [[ ! "${mirror_url}" =~ ^https?:// ]]; then + echo "(!) ${mirror_name} must start with http:// or https://" + exit 1 + fi +} + run_rvm_installer() { local install_args="$1" if [ -n "${RVM_INSTALL_MIRROR:-}" ]; then @@ -376,6 +385,8 @@ else echo "(!) Mirror values must not contain newlines." exit 1 fi + validate_mirror_url "RUBY_SOURCE_MIRROR" "${RUBY_SOURCE_MIRROR:-}" + validate_mirror_url "RUBY_BINARIES_MIRROR" "${RUBY_BINARIES_MIRROR:-}" if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -Fqx "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" /etc/rvmrc 2>/dev/null; then echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc fi From 8ae21568b119f232648535bc334698094a228488 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:32:25 +0000 Subject: [PATCH 07/21] fix: safely quote ruby mirror values in /etc/rvmrc Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/ruby/install.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ruby/install.sh b/src/ruby/install.sh index aeedafb8f..1075a7522 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -387,11 +387,21 @@ else fi validate_mirror_url "RUBY_SOURCE_MIRROR" "${RUBY_SOURCE_MIRROR:-}" validate_mirror_url "RUBY_BINARIES_MIRROR" "${RUBY_BINARIES_MIRROR:-}" - if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -Fqx "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" /etc/rvmrc 2>/dev/null; then - echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc + if [ -n "${RUBY_SOURCE_MIRROR:-}" ]; then + ruby_source_mirror_escaped="$(printf "%s" "${RUBY_SOURCE_MIRROR}" | sed "s/'/'\"'\"'/g")" + ruby_source_line_quoted="rvm_rubies_url='${ruby_source_mirror_escaped}'" + ruby_source_line_plain="rvm_rubies_url=${RUBY_SOURCE_MIRROR}" + if ! grep -Fqx "${ruby_source_line_quoted}" /etc/rvmrc 2>/dev/null && ! grep -Fqx "${ruby_source_line_plain}" /etc/rvmrc 2>/dev/null; then + echo "${ruby_source_line_quoted}" >> /etc/rvmrc + fi fi - if [ -n "${RUBY_BINARIES_MIRROR:-}" ] && ! grep -Fqx "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" /etc/rvmrc 2>/dev/null; then - echo "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" >> /etc/rvmrc + if [ -n "${RUBY_BINARIES_MIRROR:-}" ]; then + ruby_binaries_mirror_escaped="$(printf "%s" "${RUBY_BINARIES_MIRROR}" | sed "s/'/'\"'\"'/g")" + ruby_binaries_line_quoted="rvm_binaries_url='${ruby_binaries_mirror_escaped}'" + ruby_binaries_line_plain="rvm_binaries_url=${RUBY_BINARIES_MIRROR}" + if ! grep -Fqx "${ruby_binaries_line_quoted}" /etc/rvmrc 2>/dev/null && ! grep -Fqx "${ruby_binaries_line_plain}" /etc/rvmrc 2>/dev/null; then + echo "${ruby_binaries_line_quoted}" >> /etc/rvmrc + fi fi # Install rvm run_rvm_installer "${RVM_INSTALL_ARGS}" || install_previous_version From 5459890f80fc2fbfc40e1578c4c98c269799dde0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:33:18 +0000 Subject: [PATCH 08/21] fix: validate RVM_INSTALL_MIRROR input for safe bootstrap Agent-Logs-Url: https://github.com/bbartels/features/sessions/47fca3d3-4eb7-487d-9af5-e4b462552066 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/ruby/install.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ruby/install.sh b/src/ruby/install.sh index 1075a7522..6dbd40ec8 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -340,6 +340,11 @@ validate_mirror_url() { run_rvm_installer() { local install_args="$1" if [ -n "${RVM_INSTALL_MIRROR:-}" ]; then + if [[ "${RVM_INSTALL_MIRROR}" == *$'\n'* ]]; then + echo "(!) RVM_INSTALL_MIRROR must not contain newlines." + exit 1 + fi + validate_mirror_url "RVM_INSTALL_MIRROR" "${RVM_INSTALL_MIRROR}" local rvm_tmp_dir rvm_tmp_dir="$(mktemp -d)" git clone --depth=1 "${RVM_INSTALL_MIRROR}/rvm/rvm.git" "${rvm_tmp_dir}/rvm" From 4832ef90a9f55e126395708753fbb4fa5e5827b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:03:52 +0000 Subject: [PATCH 09/21] fix(powershell): restore aka.ms version resolution with resilient fallback Agent-Logs-Url: https://github.com/bbartels/features/sessions/e1ae3385-4a58-45e6-ab36-dd2e1c4ea537 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index 4e68e5854..13a6de6e1 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -50,6 +50,70 @@ clean_cache() { rm -rf /var/cache/dnf/* fi } + +# Function to resolve PowerShell version from Microsoft redirect URLs +resolve_powershell_version() { + local version_tag="$1" + local redirect_url="https://aka.ms/powershell-release?tag=${version_tag}" + local resolved_url + local resolved_version + + set +e + resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${redirect_url}") + set -e + + resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "") + if [ -n "${resolved_version}" ]; then + echo "${resolved_version}" + return 0 + fi + + echo "Warning: Failed to resolve version from ${redirect_url}. Trying fallback release metadata." >&2 + resolve_powershell_version_from_release_metadata "${version_tag}" +} + +# Fallback resolver for environments where aka.ms is unavailable. +resolve_powershell_version_from_release_metadata() { + local version_tag="$1" + local metadata_url + local metadata="" + local resolved_version="" + local fallback_urls=( + "${GITHUB_RELEASE_URL}/PowerShell/PowerShell/raw/master/tools/metadata.json" + "https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/metadata.json" + ) + + for metadata_url in "${fallback_urls[@]}"; do + metadata="$(curl -fsSL "${metadata_url}" 2>/dev/null || true)" + if [ -n "${metadata}" ]; then + break + fi + done + + if [ -z "${metadata}" ]; then + echo "Warning: Could not fetch PowerShell release metadata from fallback URLs." >&2 + return 1 + fi + + case "${version_tag}" in + stable|latest) + resolved_version="$(echo "${metadata}" | grep -oP '"StableReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" + ;; + preview) + resolved_version="$(echo "${metadata}" | grep -oP '"PreviewReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" + ;; + lts) + resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*\[\s*"v\K[^"]+' | head -n 1 || true)" + ;; + esac + + if [ -z "${resolved_version}" ]; then + echo "Warning: Could not determine ${version_tag} version from release metadata." >&2 + return 1 + fi + + echo "${resolved_version}" +} # Install dependencies for RHEL/CentOS/AlmaLinux (DNF-based systems) install_using_dnf() { dnf remove -y curl-minimal @@ -412,6 +476,17 @@ install_using_github() { if ! type pwsh >/dev/null 2>&1; then export DEBIAN_FRONTEND=noninteractive + if [ "${POWERSHELL_VERSION}" = "lts" ] || [ "${POWERSHELL_VERSION}" = "stable" ] || [ "${POWERSHELL_VERSION}" = "preview" ]; then + echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from aka.ms..." + resolved_version="$(resolve_powershell_version "${POWERSHELL_VERSION}" || true)" + if [ -n "${resolved_version}" ]; then + echo "Resolved '${POWERSHELL_VERSION}' to version: ${resolved_version}" + POWERSHELL_VERSION="${resolved_version}" + else + echo "Warning: Could not resolve '${POWERSHELL_VERSION}' version. Falling back to 'latest'." + POWERSHELL_VERSION="latest" + fi + fi # Source /etc/os-release to get OS info . /etc/os-release From b88bf1b96c82564b1c12c8c439c0025cc717d11d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:04:25 +0000 Subject: [PATCH 10/21] chore(powershell): address validation feedback on fallback resolver Agent-Logs-Url: https://github.com/bbartels/features/sessions/e1ae3385-4a58-45e6-ab36-dd2e1c4ea537 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index 13a6de6e1..e2d4a4639 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -62,7 +62,7 @@ resolve_powershell_version() { resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${redirect_url}") set -e - resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "") + resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.[0-9]+)?' || echo "") if [ -n "${resolved_version}" ]; then echo "${resolved_version}" return 0 @@ -96,7 +96,7 @@ resolve_powershell_version_from_release_metadata() { fi case "${version_tag}" in - stable|latest) + stable) resolved_version="$(echo "${metadata}" | grep -oP '"StableReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" ;; preview) From 8e07b481bbd2fb6ffa1f6c5664762ea49b09fb67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:05:13 +0000 Subject: [PATCH 11/21] fix(powershell): harden version parsing and metadata fallback diagnostics Agent-Logs-Url: https://github.com/bbartels/features/sessions/e1ae3385-4a58-45e6-ab36-dd2e1c4ea537 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index e2d4a4639..872bc863b 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -62,7 +62,7 @@ resolve_powershell_version() { resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${redirect_url}") set -e - resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.[0-9]+)?' || echo "") + resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-[^/]+)?' || echo "") if [ -n "${resolved_version}" ]; then echo "${resolved_version}" return 0 @@ -84,9 +84,15 @@ resolve_powershell_version_from_release_metadata() { ) for metadata_url in "${fallback_urls[@]}"; do - metadata="$(curl -fsSL "${metadata_url}" 2>/dev/null || true)" - if [ -n "${metadata}" ]; then + set +e + metadata="$(curl -fsSL "${metadata_url}" 2>&1)" + curl_exit_code=$? + set -e + + if [ "${curl_exit_code}" = "0" ]; then break + else + echo "Warning: Failed to fetch PowerShell release metadata from ${metadata_url}: ${metadata}" >&2 fi done @@ -104,6 +110,9 @@ resolve_powershell_version_from_release_metadata() { ;; lts) resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*\[\s*"v\K[^"]+' | head -n 1 || true)" + if [ -z "${resolved_version}" ]; then + resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" + fi ;; esac From aa0d4dcc6475ab535dc227b58ed3e887c1dd9fe9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:05:58 +0000 Subject: [PATCH 12/21] fix(powershell): handle metadata fetch failures correctly Agent-Logs-Url: https://github.com/bbartels/features/sessions/e1ae3385-4a58-45e6-ab36-dd2e1c4ea537 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index 872bc863b..fa50d8983 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -62,7 +62,7 @@ resolve_powershell_version() { resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${redirect_url}") set -e - resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-[^/]+)?' || echo "") + resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9-]+(\.[0-9]+)?)?' || echo "") if [ -n "${resolved_version}" ]; then echo "${resolved_version}" return 0 @@ -76,8 +76,10 @@ resolve_powershell_version() { resolve_powershell_version_from_release_metadata() { local version_tag="$1" local metadata_url + local curl_error local metadata="" local resolved_version="" + local metadata_fetched="false" local fallback_urls=( "${GITHUB_RELEASE_URL}/PowerShell/PowerShell/raw/master/tools/metadata.json" "https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/metadata.json" @@ -90,13 +92,16 @@ resolve_powershell_version_from_release_metadata() { set -e if [ "${curl_exit_code}" = "0" ]; then + metadata_fetched="true" break else - echo "Warning: Failed to fetch PowerShell release metadata from ${metadata_url}: ${metadata}" >&2 + curl_error="${metadata}" + metadata="" + echo "Warning: Failed to fetch PowerShell release metadata from ${metadata_url}: ${curl_error}" >&2 fi done - if [ -z "${metadata}" ]; then + if [ "${metadata_fetched}" != "true" ] || [ -z "${metadata}" ]; then echo "Warning: Could not fetch PowerShell release metadata from fallback URLs." >&2 return 1 fi @@ -111,6 +116,7 @@ resolve_powershell_version_from_release_metadata() { lts) resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*\[\s*"v\K[^"]+' | head -n 1 || true)" if [ -z "${resolved_version}" ]; then + # LTSReleaseTag can be either an array or a string depending on metadata schema. resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" fi ;; From fb764c5fb2f9626c19a3be344da317090c97e6a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:14:00 +0000 Subject: [PATCH 13/21] fix: restore kubectl secondary fallback URL and simplify ruby rvmrc mirror writes Agent-Logs-Url: https://github.com/bbartels/features/sessions/58d9ab00-c56e-435b-a7c0-72bc0d413cdb Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/kubectl-helm-minikube/install.sh | 6 +++++- src/ruby/install.sh | 30 ++++------------------------ 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index 82a47afe5..8811e0e77 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -173,7 +173,11 @@ if [ ${KUBECTL_VERSION} != "none" ]; then if [ "${KUBECTL_VERSION}" = "latest" ] || [ "${KUBECTL_VERSION}" = "lts" ] || [ "${KUBECTL_VERSION}" = "current" ] || [ "${KUBECTL_VERSION}" = "stable" ]; then KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 "${KUBECTL_MIRROR}/release/stable.txt" 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" if [ -z "${KUBECTL_VERSION}" ]; then - echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}. Using fallback version ${KUBECTL_FALLBACK_VERSION}" + echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}, trying alternative URL..." + KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 https://storage.googleapis.com/kubernetes-release/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" + fi + if [ -z "${KUBECTL_VERSION}" ]; then + echo "(!) Failed to fetch kubectl stable version from both URLs. Using fallback version ${KUBECTL_FALLBACK_VERSION}" KUBECTL_VERSION="${KUBECTL_FALLBACK_VERSION}" fi else diff --git a/src/ruby/install.sh b/src/ruby/install.sh index 6dbd40ec8..ef1bc54c6 100755 --- a/src/ruby/install.sh +++ b/src/ruby/install.sh @@ -328,15 +328,6 @@ set_rvm_install_args() { fi } -validate_mirror_url() { - local mirror_name="$1" - local mirror_url="$2" - if [ -n "${mirror_url}" ] && [[ ! "${mirror_url}" =~ ^https?:// ]]; then - echo "(!) ${mirror_name} must start with http:// or https://" - exit 1 - fi -} - run_rvm_installer() { local install_args="$1" if [ -n "${RVM_INSTALL_MIRROR:-}" ]; then @@ -344,7 +335,6 @@ run_rvm_installer() { echo "(!) RVM_INSTALL_MIRROR must not contain newlines." exit 1 fi - validate_mirror_url "RVM_INSTALL_MIRROR" "${RVM_INSTALL_MIRROR}" local rvm_tmp_dir rvm_tmp_dir="$(mktemp -d)" git clone --depth=1 "${RVM_INSTALL_MIRROR}/rvm/rvm.git" "${rvm_tmp_dir}/rvm" @@ -390,23 +380,11 @@ else echo "(!) Mirror values must not contain newlines." exit 1 fi - validate_mirror_url "RUBY_SOURCE_MIRROR" "${RUBY_SOURCE_MIRROR:-}" - validate_mirror_url "RUBY_BINARIES_MIRROR" "${RUBY_BINARIES_MIRROR:-}" - if [ -n "${RUBY_SOURCE_MIRROR:-}" ]; then - ruby_source_mirror_escaped="$(printf "%s" "${RUBY_SOURCE_MIRROR}" | sed "s/'/'\"'\"'/g")" - ruby_source_line_quoted="rvm_rubies_url='${ruby_source_mirror_escaped}'" - ruby_source_line_plain="rvm_rubies_url=${RUBY_SOURCE_MIRROR}" - if ! grep -Fqx "${ruby_source_line_quoted}" /etc/rvmrc 2>/dev/null && ! grep -Fqx "${ruby_source_line_plain}" /etc/rvmrc 2>/dev/null; then - echo "${ruby_source_line_quoted}" >> /etc/rvmrc - fi + if [ -n "${RUBY_SOURCE_MIRROR:-}" ] && ! grep -Fqx "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" /etc/rvmrc 2>/dev/null; then + echo "rvm_rubies_url=${RUBY_SOURCE_MIRROR}" >> /etc/rvmrc fi - if [ -n "${RUBY_BINARIES_MIRROR:-}" ]; then - ruby_binaries_mirror_escaped="$(printf "%s" "${RUBY_BINARIES_MIRROR}" | sed "s/'/'\"'\"'/g")" - ruby_binaries_line_quoted="rvm_binaries_url='${ruby_binaries_mirror_escaped}'" - ruby_binaries_line_plain="rvm_binaries_url=${RUBY_BINARIES_MIRROR}" - if ! grep -Fqx "${ruby_binaries_line_quoted}" /etc/rvmrc 2>/dev/null && ! grep -Fqx "${ruby_binaries_line_plain}" /etc/rvmrc 2>/dev/null; then - echo "${ruby_binaries_line_quoted}" >> /etc/rvmrc - fi + if [ -n "${RUBY_BINARIES_MIRROR:-}" ] && ! grep -Fqx "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" /etc/rvmrc 2>/dev/null; then + echo "rvm_binaries_url=${RUBY_BINARIES_MIRROR}" >> /etc/rvmrc fi # Install rvm run_rvm_installer "${RVM_INSTALL_ARGS}" || install_previous_version From a4b5d813f0f9d0af0197e0ff0a1a33e076e55a3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:39:29 +0000 Subject: [PATCH 14/21] revert: restore powershell to upstream form, keeping only mirror URL additions Agent-Logs-Url: https://github.com/bbartels/features/sessions/e372413f-942b-4e04-bc36-e4e1d8707978 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 85 ++++++--------------------------------- 1 file changed, 13 insertions(+), 72 deletions(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index fa50d8983..a5fe07ef4 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -50,83 +50,24 @@ clean_cache() { rm -rf /var/cache/dnf/* fi } - # Function to resolve PowerShell version from Microsoft redirect URLs resolve_powershell_version() { local version_tag="$1" local redirect_url="https://aka.ms/powershell-release?tag=${version_tag}" + + # Follow the redirect and extract the version from the final URL local resolved_url + resolved_url=$(curl -sSL -o /dev/null -w '%{url_effective}' "${redirect_url}") + + # Extract version from URL (e.g., https://github.com/PowerShell/PowerShell/releases/tag/v7.4.7 -> 7.4.7) local resolved_version - - set +e - resolved_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' "${redirect_url}") - set -e - - resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9-]+(\.[0-9]+)?)?' || echo "") - if [ -n "${resolved_version}" ]; then - echo "${resolved_version}" - return 0 - fi - - echo "Warning: Failed to resolve version from ${redirect_url}. Trying fallback release metadata." >&2 - resolve_powershell_version_from_release_metadata "${version_tag}" -} - -# Fallback resolver for environments where aka.ms is unavailable. -resolve_powershell_version_from_release_metadata() { - local version_tag="$1" - local metadata_url - local curl_error - local metadata="" - local resolved_version="" - local metadata_fetched="false" - local fallback_urls=( - "${GITHUB_RELEASE_URL}/PowerShell/PowerShell/raw/master/tools/metadata.json" - "https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/metadata.json" - ) - - for metadata_url in "${fallback_urls[@]}"; do - set +e - metadata="$(curl -fsSL "${metadata_url}" 2>&1)" - curl_exit_code=$? - set -e - - if [ "${curl_exit_code}" = "0" ]; then - metadata_fetched="true" - break - else - curl_error="${metadata}" - metadata="" - echo "Warning: Failed to fetch PowerShell release metadata from ${metadata_url}: ${curl_error}" >&2 - fi - done - - if [ "${metadata_fetched}" != "true" ] || [ -z "${metadata}" ]; then - echo "Warning: Could not fetch PowerShell release metadata from fallback URLs." >&2 - return 1 - fi - - case "${version_tag}" in - stable) - resolved_version="$(echo "${metadata}" | grep -oP '"StableReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" - ;; - preview) - resolved_version="$(echo "${metadata}" | grep -oP '"PreviewReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" - ;; - lts) - resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*\[\s*"v\K[^"]+' | head -n 1 || true)" - if [ -z "${resolved_version}" ]; then - # LTSReleaseTag can be either an array or a string depending on metadata schema. - resolved_version="$(echo "${metadata}" | grep -oP '"LTSReleaseTag"\s*:\s*"v\K[^"]+' | head -n 1 || true)" - fi - ;; - esac - + resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "") + if [ -z "${resolved_version}" ]; then - echo "Warning: Could not determine ${version_tag} version from release metadata." >&2 + echo "Failed to resolve version for tag: ${version_tag}" >&2 return 1 fi - + echo "${resolved_version}" } # Install dependencies for RHEL/CentOS/AlmaLinux (DNF-based systems) @@ -492,8 +433,8 @@ install_using_github() { if ! type pwsh >/dev/null 2>&1; then export DEBIAN_FRONTEND=noninteractive if [ "${POWERSHELL_VERSION}" = "lts" ] || [ "${POWERSHELL_VERSION}" = "stable" ] || [ "${POWERSHELL_VERSION}" = "preview" ]; then - echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from aka.ms..." - resolved_version="$(resolve_powershell_version "${POWERSHELL_VERSION}" || true)" + echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from Microsoft..." + resolved_version=$(resolve_powershell_version "${POWERSHELL_VERSION}") if [ -n "${resolved_version}" ]; then echo "Resolved '${POWERSHELL_VERSION}' to version: ${resolved_version}" POWERSHELL_VERSION="${resolved_version}" @@ -501,8 +442,8 @@ if ! type pwsh >/dev/null 2>&1; then echo "Warning: Could not resolve '${POWERSHELL_VERSION}' version. Falling back to 'latest'." POWERSHELL_VERSION="latest" fi - fi - + fi + # Source /etc/os-release to get OS info . /etc/os-release architecture="$(uname -m)" From c7a13592d3a7a072da3314ca82821b7f951eee3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:48:11 +0000 Subject: [PATCH 15/21] feat: add minimal metadata.json fallback when aka.ms is unreachable Agent-Logs-Url: https://github.com/bbartels/features/sessions/fc3bae77-8d60-43af-970f-a51666be21e4 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/powershell/install.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index a5fe07ef4..5a81ce9b0 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -63,6 +63,18 @@ resolve_powershell_version() { local resolved_version resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "") + if [ -z "${resolved_version}" ]; then + # Fallback: fetch version from PowerShell metadata.json via GitHub + local metadata_url="${GITHUB_RELEASE_MIRROR:-https://raw.githubusercontent.com}/PowerShell/PowerShell/master/tools/metadata.json" + local metadata + metadata=$(curl -sSL "${metadata_url}" 2>/dev/null || echo "") + case "${version_tag}" in + lts) resolved_version=$(echo "${metadata}" | grep -oP '"LtsReleaseTag":\s*"v\K[^"]+') ;; + preview) resolved_version=$(echo "${metadata}" | grep -oP '"PreviewReleaseTag":\s*"v\K[^"]+') ;; + *) resolved_version=$(echo "${metadata}" | grep -oP '"StableReleaseTag":\s*"v\K[^"]+') ;; + esac + fi + if [ -z "${resolved_version}" ]; then echo "Failed to resolve version for tag: ${version_tag}" >&2 return 1 From e8a08afe7395181274e37d04d07694343ba9311d Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 14 Apr 2026 01:54:59 +0100 Subject: [PATCH 16/21] Apply suggestions from code review Co-authored-by: Benjamin Bartels --- src/powershell/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index 5a81ce9b0..d0df2a277 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -17,6 +17,7 @@ POWERSHELL_MODULES="${MODULES:-""}" POWERSHELL_PROFILE_URL="${POWERSHELLPROFILEURL}" MICROSOFT_PACKAGES_MIRROR="${MICROSOFT_PACKAGES_MIRROR:-https://packages.microsoft.com}" GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" +GITHUB_USERCONTENT_URL="${GITHUB_USERCONTENT_MIRROR:-https://raw.githubusercontent.com}" MICROSOFT_GPG_KEYS_URI="${MICROSOFT_PACKAGES_MIRROR}/keys/microsoft.asc" #MICROSOFT_GPG_KEYS_URI=$(curl https://packages.microsoft.com/keys/microsoft.asc -o /usr/share/keyrings/microsoft-archive-keyring.gpg) @@ -65,7 +66,7 @@ resolve_powershell_version() { if [ -z "${resolved_version}" ]; then # Fallback: fetch version from PowerShell metadata.json via GitHub - local metadata_url="${GITHUB_RELEASE_MIRROR:-https://raw.githubusercontent.com}/PowerShell/PowerShell/master/tools/metadata.json" + local metadata_url="${GITHUB_USERCONTENT_MIRROR}/PowerShell/PowerShell/master/tools/metadata.json" local metadata metadata=$(curl -sSL "${metadata_url}" 2>/dev/null || echo "") case "${version_tag}" in From 76ca4eee1f21374133107e27f0ca4d33ba725eac Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 14 Apr 2026 02:00:17 +0100 Subject: [PATCH 17/21] Apply suggestion from @bbartels --- src/powershell/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powershell/install.sh b/src/powershell/install.sh index d0df2a277..9fa39c504 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -66,7 +66,7 @@ resolve_powershell_version() { if [ -z "${resolved_version}" ]; then # Fallback: fetch version from PowerShell metadata.json via GitHub - local metadata_url="${GITHUB_USERCONTENT_MIRROR}/PowerShell/PowerShell/master/tools/metadata.json" + local metadata_url="${GITHUB_USERCONTENT_URL}/PowerShell/PowerShell/master/tools/metadata.json" local metadata metadata=$(curl -sSL "${metadata_url}" 2>/dev/null || echo "") case "${version_tag}" in From 9aab57c27f0db867022d68d67d87ddd0b5c52a64 Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 14 Apr 2026 02:06:19 +0100 Subject: [PATCH 18/21] Apply suggestions from code review Co-authored-by: Benjamin Bartels --- src/kubectl-helm-minikube/install.sh | 3 ++- src/terraform/install.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index 8811e0e77..ee8a53a80 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -22,6 +22,7 @@ KUBECTL_MIRROR="${KUBECTL_MIRROR:-https://dl.k8s.io}" HELM_MIRROR="${HELM_MIRROR:-https://get.helm.sh}" MINIKUBE_MIRROR="${MINIKUBE_MIRROR:-https://storage.googleapis.com/minikube}" GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" +KUBECTL_GCS_MIRROR="${KUBECTL_GCS_MIRROR:-https://storage.googleapis.com/kubernetes-release}" KUBECTL_SHA256="${KUBECTL_SHA256:-"automatic"}" HELM_SHA256="${HELM_SHA256:-"automatic"}" @@ -174,7 +175,7 @@ if [ ${KUBECTL_VERSION} != "none" ]; then KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 "${KUBECTL_MIRROR}/release/stable.txt" 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" if [ -z "${KUBECTL_VERSION}" ]; then echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}, trying alternative URL..." - KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 https://storage.googleapis.com/kubernetes-release/release/stable.txt 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" + KUBECTL_VERSION="$(curl -fsSL --connect-timeout 10 --max-time 30 "${KUBECTL_GCS_MIRROR}/release/stable.txt" 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' || echo "")" fi if [ -z "${KUBECTL_VERSION}" ]; then echo "(!) Failed to fetch kubectl stable version from both URLs. Using fallback version ${KUBECTL_FALLBACK_VERSION}" diff --git a/src/terraform/install.sh b/src/terraform/install.sh index 53f9f21b0..826167cd0 100755 --- a/src/terraform/install.sh +++ b/src/terraform/install.sh @@ -29,6 +29,7 @@ SENTINEL_SHA256="${SENTINEL_SHA256:-"automatic"}" TFSEC_SHA256="${TFSEC_SHA256:-"automatic"}" TERRAFORM_DOCS_SHA256="${TERRAFORM_DOCS_SHA256:-"automatic"}" GITHUB_RELEASE_URL="${GITHUB_RELEASE_MIRROR:-https://github.com}" +GITHUB_USERCONTENT_URL="${GITHUB_USERCONTENT_MIRROR:-https://raw.githubusercontent.com}" HASHICORP_RELEASES_URL="https://releases.hashicorp.com" if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then @@ -36,7 +37,7 @@ if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then fi TERRAFORM_GPG_KEY="72D7468F" -TFLINT_GPG_KEY_URI="https://raw.githubusercontent.com/terraform-linters/tflint/v0.46.1/8CE69160EB3F2FE9.key" +TFLINT_GPG_KEY_URI="${GITHUB_USERCONTENT_URL}/terraform-linters/tflint/v0.46.1/8CE69160EB3F2FE9.key" HASHICORP_KEY_URL="${HASHICORP_GPG_KEY_MIRROR:-https://keybase.io}/hashicorp/pgp_keys.asc" KEYSERVER_PROXY="${HTTPPROXY:-"${HTTP_PROXY:-""}"}" From 0f7841c3a73f7c313ffe9e10355e7b4f164186fc Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 14 Apr 2026 02:10:13 +0100 Subject: [PATCH 19/21] Apply suggestion from @bbartels --- src/kubectl-helm-minikube/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index ee8a53a80..d8a23c372 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -190,7 +190,7 @@ if [ ${KUBECTL_VERSION} != "none" ]; then curl -sSL -o /usr/local/bin/kubectl "${KUBECTL_MIRROR}/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" chmod 0755 /usr/local/bin/kubectl if [ "$KUBECTL_SHA256" = "automatic" ]; then - KUBECTL_SHA256="$(curl -sSL "${KUBECTL_MIRROR}/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" + KUBECTL_SHA256="$(curl -sSL "${KUBECTL_MIRROR}/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" fi ([ "${KUBECTL_SHA256}" = "dev-mode" ] || (echo "${KUBECTL_SHA256} */usr/local/bin/kubectl" | sha256sum -c -)) if ! type kubectl > /dev/null 2>&1; then From f4fcf6e75cdcfee948ec446e53366410b2197098 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 01:18:14 +0000 Subject: [PATCH 20/21] Initial plan From eb0d3545e0ffe438c2f0847a9afa856004c4fe14 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 01:19:48 +0000 Subject: [PATCH 21/21] chore: bump minor versions for mirror/keyserver feature updates Agent-Logs-Url: https://github.com/bbartels/features/sessions/f4770407-c8bf-457f-91d4-9ed1af88d766 Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com> --- src/docker-in-docker/devcontainer-feature.json | 2 +- src/dotnet/devcontainer-feature.json | 2 +- src/github-cli/devcontainer-feature.json | 2 +- src/go/devcontainer-feature.json | 2 +- src/java/devcontainer-feature.json | 2 +- src/kubectl-helm-minikube/devcontainer-feature.json | 2 +- src/node/devcontainer-feature.json | 2 +- src/nvidia-cuda/devcontainer-feature.json | 2 +- src/php/devcontainer-feature.json | 2 +- src/powershell/devcontainer-feature.json | 2 +- src/python/devcontainer-feature.json | 2 +- src/ruby/devcontainer-feature.json | 2 +- src/rust/devcontainer-feature.json | 2 +- src/terraform/devcontainer-feature.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/docker-in-docker/devcontainer-feature.json b/src/docker-in-docker/devcontainer-feature.json index 4c792e8f4..bdb4cb291 100644 --- a/src/docker-in-docker/devcontainer-feature.json +++ b/src/docker-in-docker/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "docker-in-docker", - "version": "2.16.1", + "version": "2.17.0", "name": "Docker (Docker-in-Docker)", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", diff --git a/src/dotnet/devcontainer-feature.json b/src/dotnet/devcontainer-feature.json index 4bd3168c7..fb62c7fa8 100644 --- a/src/dotnet/devcontainer-feature.json +++ b/src/dotnet/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "dotnet", - "version": "2.5.0", + "version": "2.6.0", "name": "Dotnet CLI", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet", "description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.", diff --git a/src/github-cli/devcontainer-feature.json b/src/github-cli/devcontainer-feature.json index 15a91e43d..d230adbcd 100644 --- a/src/github-cli/devcontainer-feature.json +++ b/src/github-cli/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "github-cli", - "version": "1.1.0", + "version": "1.2.0", "name": "GitHub CLI", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/github-cli", "description": "Installs the GitHub CLI. Auto-detects latest version and installs needed dependencies.", diff --git a/src/go/devcontainer-feature.json b/src/go/devcontainer-feature.json index 8872d6374..606069da9 100644 --- a/src/go/devcontainer-feature.json +++ b/src/go/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "go", - "version": "1.3.3", + "version": "1.4.0", "name": "Go", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/go", "description": "Installs Go and common Go utilities. Auto-detects latest version and installs needed dependencies.", diff --git a/src/java/devcontainer-feature.json b/src/java/devcontainer-feature.json index c82718a49..8a9980c94 100644 --- a/src/java/devcontainer-feature.json +++ b/src/java/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "java", - "version": "1.8.0", + "version": "1.9.0", "name": "Java (via SDKMAN!)", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/java", "description": "Installs Java, SDKMAN! (if not installed), and needed dependencies.", diff --git a/src/kubectl-helm-minikube/devcontainer-feature.json b/src/kubectl-helm-minikube/devcontainer-feature.json index a88aebde6..c1e5d001a 100644 --- a/src/kubectl-helm-minikube/devcontainer-feature.json +++ b/src/kubectl-helm-minikube/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "kubectl-helm-minikube", - "version": "1.3.1", + "version": "1.4.0", "name": "Kubectl, Helm, and Minikube", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/kubectl-helm-minikube", "description": "Installs latest version of kubectl, Helm, and optionally minikube. Auto-detects latest versions and installs needed dependencies.", diff --git a/src/node/devcontainer-feature.json b/src/node/devcontainer-feature.json index c8ceb966f..9570d556a 100644 --- a/src/node/devcontainer-feature.json +++ b/src/node/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "node", - "version": "1.7.1", + "version": "1.8.0", "name": "Node.js (via nvm), yarn and pnpm.", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/node", "description": "Installs Node.js, nvm, yarn, pnpm, and needed dependencies.", diff --git a/src/nvidia-cuda/devcontainer-feature.json b/src/nvidia-cuda/devcontainer-feature.json index 477faf17a..2b660206d 100644 --- a/src/nvidia-cuda/devcontainer-feature.json +++ b/src/nvidia-cuda/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "nvidia-cuda", - "version": "3.0.0", + "version": "3.1.0", "name": "NVIDIA CUDA", "description": "Installs shared libraries for NVIDIA CUDA.", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/nvidia-cuda", diff --git a/src/php/devcontainer-feature.json b/src/php/devcontainer-feature.json index 4db478230..5c8bf040d 100644 --- a/src/php/devcontainer-feature.json +++ b/src/php/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "php", - "version": "1.1.4", + "version": "1.2.0", "name": "PHP", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/php", "options": { diff --git a/src/powershell/devcontainer-feature.json b/src/powershell/devcontainer-feature.json index 009f4c238..ecd09eec6 100644 --- a/src/powershell/devcontainer-feature.json +++ b/src/powershell/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "powershell", - "version": "2.0.2", + "version": "2.1.0", "name": "PowerShell", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/powershell", "description": "Installs PowerShell along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.", diff --git a/src/python/devcontainer-feature.json b/src/python/devcontainer-feature.json index 6a4121415..218977bb3 100644 --- a/src/python/devcontainer-feature.json +++ b/src/python/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "python", - "version": "1.8.0", + "version": "1.9.0", "name": "Python", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/python", "description": "Installs the provided version of Python, as well as PIPX, and other common Python utilities. JupyterLab is conditionally installed with the python feature. Note: May require source code compilation.", diff --git a/src/ruby/devcontainer-feature.json b/src/ruby/devcontainer-feature.json index 661c46bf0..ea2b33f65 100644 --- a/src/ruby/devcontainer-feature.json +++ b/src/ruby/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "ruby", - "version": "1.3.2", + "version": "1.4.0", "name": "Ruby (via rvm)", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/ruby", "description": "Installs Ruby, rvm, rbenv, common Ruby utilities, and needed dependencies.", diff --git a/src/rust/devcontainer-feature.json b/src/rust/devcontainer-feature.json index 88b64daed..e51c6e2ce 100644 --- a/src/rust/devcontainer-feature.json +++ b/src/rust/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "rust", - "version": "1.5.0", + "version": "1.6.0", "name": "Rust", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/rust", "description": "Installs Rust, common Rust utilities, and their required dependencies", diff --git a/src/terraform/devcontainer-feature.json b/src/terraform/devcontainer-feature.json index a72f18993..b8d04b608 100644 --- a/src/terraform/devcontainer-feature.json +++ b/src/terraform/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "terraform", - "version": "1.4.2", + "version": "1.5.0", "name": "Terraform, tflint, and TFGrunt", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/terraform", "description": "Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects latest version and installs needed dependencies.",