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/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 5af320b0b..bb1d264e3 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -17,8 +17,11 @@ 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}" +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 +332,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 +356,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 +384,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 +439,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 +611,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 +688,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 +708,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 +730,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 +738,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 +754,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 +779,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 +814,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 +833,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/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/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/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/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/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/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/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/java/install.sh b/src/java/install.sh index 988460307..c3ab5f406 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,17 @@ 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 + 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 # Disable native CLI in config to prevent future usage 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/kubectl-helm-minikube/install.sh b/src/kubectl-helm-minikube/install.sh index 40901d3cb..d8a23c372 100755 --- a/src/kubectl-helm-minikube/install.sh +++ b/src/kubectl-helm-minikube/install.sh @@ -18,6 +18,11 @@ 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_GCS_MIRROR="${KUBECTL_GCS_MIRROR:-https://storage.googleapis.com/kubernetes-release}" KUBECTL_SHA256="${KUBECTL_SHA256:-"automatic"}" HELM_SHA256="${HELM_SHA256:-"automatic"}" @@ -167,10 +172,10 @@ 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 "")" + echo "(!) Failed to fetch kubectl stable version from ${KUBECTL_MIRROR}, trying alternative URL..." + 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}" @@ -182,10 +187,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 +243,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 +314,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 +357,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/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/node/install.sh b/src/node/install.sh index 1d89abd0a..b624aede2 100755 --- a/src/node/install.sh +++ b/src/node/install.sh @@ -11,6 +11,8 @@ 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}" +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 @@ -305,6 +307,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 +354,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_ESCAPED} && . '$NVM_DIR/nvm.sh' && nvm install '${NODE_VERSION}' && nvm alias default '${NODE_VERSION}'" fi fi @@ -369,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 && . '$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/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/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/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/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/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/powershell/install.sh b/src/powershell/install.sh index cabd2cbb4..9fa39c504 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -15,8 +15,11 @@ 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}" +GITHUB_USERCONTENT_URL="${GITHUB_USERCONTENT_MIRROR:-https://raw.githubusercontent.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" @@ -61,6 +64,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_USERCONTENT_URL}/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 @@ -83,14 +98,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 +271,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 +380,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 +415,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 @@ -500,4 +515,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/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/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/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/ruby/install.sh b/src/ruby/install.sh index 39cb5be03..ef1bc54c6 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,29 @@ set_rvm_install_args() { fi } +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 + 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 +376,18 @@ 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 + 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 - 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/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/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/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.", diff --git a/src/terraform/install.sh b/src/terraform/install.sh index 999815a38..826167cd0 100755 --- a/src/terraform/install.sh +++ b/src/terraform/install.sh @@ -28,6 +28,8 @@ 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}" +GITHUB_USERCONTENT_URL="${GITHUB_USERCONTENT_MIRROR:-https://raw.githubusercontent.com}" HASHICORP_RELEASES_URL="https://releases.hashicorp.com" if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then @@ -35,7 +37,8 @@ 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:-""}"}" architecture="$(uname -m)" @@ -61,6 +64,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 +122,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 +340,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 +348,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 +465,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 +481,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 +504,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 +518,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 +531,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 +584,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 +600,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 +615,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 +631,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