Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/workflows/pr-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
.containerignore
collection-scripts/**
vendor/**
artifacts.lock.yaml
LICENSE
files_ignore: |
**/*.md
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/vendor-update.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,19 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

make vendor-update VENDOR_NAME="$VENDOR_NAME" VENDOR_VERSION="$VENDOR_VERSION"
if [ "$VENDOR_NAME" = "helm" ]; then
./hack/update-helm-lockfile.sh "$VENDOR_VERSION"
else
make vendor-update VENDOR_NAME="$VENDOR_NAME" VENDOR_VERSION="$VENDOR_VERSION"
fi

# Stage and commit changes (the script leaves them unstaged)
if ! git diff --quiet || ! git diff --cached --quiet; then
git add "vendor/$VENDOR_NAME" Containerfile .rhdh/docker/Containerfile Makefile
if [ "$VENDOR_NAME" = "helm" ]; then
git add artifacts.lock.yaml Makefile
else
git add "vendor/$VENDOR_NAME" Containerfile .rhdh/docker/Containerfile Makefile
fi
git commit -m "chore(vendor): update $VENDOR_NAME to $VENDOR_VERSION"
echo "changed=true" >> "$GITHUB_OUTPUT"
else
Expand Down
58 changes: 44 additions & 14 deletions .rhdh/docker/Containerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Konflux hermetic: prefetch rpm (repo root), pip (repo root), gomod (`vendor/helm`), cargo (`vendor/websocat`); network off during RUN.
# Konflux hermetic: prefetch rpm (repo root), pip (repo root), generic (helm CGW), cargo (`vendor/websocat`); network off during RUN.
#
# Stage 1: Build websocat from vendored source
# websocat v1.14.1 — update via: make vendor-update VENDOR_NAME=websocat VENDOR_VERSION=v<NEW>
Expand Down Expand Up @@ -33,20 +33,50 @@ RUN set -eu; \
cp target/release/websocat /tmp/websocat && \
/tmp/websocat --version

# Stage 2: Build helm from vendored source
# helm v4.2.3 — update via: make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v<NEW>
# https://registry.access.redhat.com/ubi9/go-toolset
FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1786351949@sha256:0b471eb04868f3d9d90bf3c668f9c6c7a22cef07474ac9fec067909dfd7dec7c AS helm-builder
COPY Makefile /tmp/Makefile
COPY vendor/helm /opt/app-root/src/helm
WORKDIR /opt/app-root/src/helm
# Stage 2a: Install helm from prefetched CGW binaries (artifacts.lock.yaml / generic fetcher)
# Comment this out and uncomment Stage 2b below when no binary available.
# https://registry.access.redhat.com/ubi9-minimal
FROM registry.access.redhat.com/ubi9-minimal:9.8-1786380870@sha256:7c372902c8d211db2d25c8277ba534a73b92742a334874dced829a63b0f21221 AS helm-builder
ARG TARGETPLATFORM
COPY hack/install-helm-binary.sh /tmp/install-helm-binary.sh
RUN set -eu; \
. /cachi2/cachi2.env; \
HELM_VERSION=$(grep '^HELM_VERSION' /tmp/Makefile | sed 's/.*:= *//'); \
CGO_ENABLED=0 go build -trimpath \
-ldflags "-X helm.sh/helm/v4/internal/version.version=v${HELM_VERSION}" \
-o /tmp/helm ./cmd/helm && \
/tmp/helm version
arch=$(uname -m); \
rm -rf /etc/yum.repos.d/*; \
if [ -d "/cachi2/output/deps/rpm/${arch}/repos.d" ]; then \
cp -a "/cachi2/output/deps/rpm/${arch}/repos.d/." /etc/yum.repos.d/; \
else \
for repod in /cachi2/output/deps/rpm/"${arch}"/*/repos.d; do \
[ -d "${repod}" ] || continue; \
suffix=$(basename "$(dirname "$repod")"); \
for rf in "${repod}"/*.repo; do \
[ -f "${rf}" ] || continue; \
install -m0644 "${rf}" "/etc/yum.repos.d/${suffix}-$(basename "${rf}")"; \
done; \
done; \
fi; \
test -n "$(ls /etc/yum.repos.d/*.repo 2>/dev/null)"; \
microdnf install -y --setopt=install_weak_deps=0 --nodocs tar gzip bash \
&& microdnf clean all; \
CONTAINER_BUILD=true TARGETPLATFORM="${TARGETPLATFORM}" \
bash /tmp/install-helm-binary.sh --prefetch; \
rm -f /tmp/install-helm-binary.sh

# Stage 2b: Build helm from vendored source (use when no binary available in Stage 2a)
# Swap with Stage 2a: comment out Stage 2a, uncomment below, and use gomod prefetch instead of generic.
# update via: make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v<NEW>
# https://registry.access.redhat.com/ubi9/go-toolset
# FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1786351949@sha256:0b471eb04868f3d9d90bf3c668f9c6c7a22cef07474ac9fec067909dfd7dec7c AS helm-builder
# COPY Makefile /tmp/Makefile
# COPY vendor/helm /opt/app-root/src/helm
# WORKDIR /opt/app-root/src/helm
# RUN set -eu; \
# . /cachi2/cachi2.env; \
# HELM_VERSION=$(grep '^HELM_VERSION' /tmp/Makefile | sed 's/.*:= *//'); \
# CGO_ENABLED=0 go build -mod=vendor -trimpath \
# -ldflags "-X helm.sh/helm/v4/internal/version.version=v${HELM_VERSION}" \
# -o /tmp/helm ./cmd/helm && \
# /tmp/helm version

# Stage 3: Final image
# https://registry.access.redhat.com/ubi9-minimal
Expand Down Expand Up @@ -95,7 +125,7 @@ RUN set -eu; \
-r /tmp/requirements.txt && \
rm -f /tmp/requirements-build.txt /tmp/requirements.txt

# Copy helm binary built from source (vendor/helm)
# Copy helm binary from prefetched CGW mirror (helm-builder stage)
COPY --from=helm-builder /tmp/helm /usr/local/bin/helm

# Copy websocat binary built from source (vendor/websocat)
Expand Down
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ fi
This project is built downstream via Konflux with hermetic builds (no network access during `docker build`). All build-time dependencies must be available locally in the repo or installable from vendored sources.

### What's vendored and why
- **helm** — prebuilt Linux binaries from the [Red Hat CGW mirror](https://mirror.openshift.com/pub/cgw/helm/) (`artifacts.lock.yaml` + Hermeto generic fetcher for Konflux; curl in upstream Containerfile). Not vendored as source when CGW publishes the version; `make local-setup` and `make vendor` fall back to `vendor/helm` when the mirror tarball is missing.
- **websocat** — vendored as a Git subtree under `vendor/websocat/` and built from Rust source in a multi-stage Containerfile. Not available as an RPM, and pre-built binary downloads are incompatible with hermetic build requirements.
- **yq** ([kislyuk/yq](https://github.com/kislyuk/yq)) — installed via `pip` in the Containerfile. It is a thin Python wrapper around jq for YAML processing, so vendoring is not needed — pip can install from a pre-fetched package index in hermetic mode.

Expand All @@ -97,6 +98,7 @@ make vendor
To update a specific dependency to a new version (also bumps the version in the Makefile and Containerfile):
```bash
make vendor-update VENDOR_NAME=websocat VENDOR_VERSION=v1.14.1
make helm-lockfile-update # refresh artifacts.lock.yaml when HELM_VERSION changes
```
A weekly GitHub Actions workflow (`vendor-update.yaml`) checks for new releases and auto-creates PRs.

Expand Down
40 changes: 28 additions & 12 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,34 @@ RUN cargo build --release \
cp target/release/websocat /tmp/websocat && \
/tmp/websocat --version

# Stage 2: Build helm from vendored source
# update helm version via: make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v<NEW>
# Stage 2a: Install helm from Red Hat CGW mirror (default)
# Comment this out and uncomment Stage 2b below when no binary available.
# https://registry.access.redhat.com/ubi9-minimal
FROM registry.access.redhat.com/ubi9-minimal:9.8-1786380870@sha256:7c372902c8d211db2d25c8277ba534a73b92742a334874dced829a63b0f21221 AS helm-builder
ARG TARGETPLATFORM
COPY Makefile artifacts.lock.yaml /tmp/
COPY hack/install-helm-binary.sh hack/verify-helm-tarball.sh /tmp/
RUN microdnf install -y --setopt=install_weak_deps=0 --nodocs tar gzip bash \
&& microdnf clean all \
&& HELM_VERSION=$(grep '^HELM_VERSION' /tmp/Makefile | sed 's/.*:= *//') \
&& CONTAINER_BUILD=true TARGETPLATFORM="${TARGETPLATFORM}" HELM_VERSION="${HELM_VERSION}" \
LOCKFILE=/tmp/artifacts.lock.yaml VERIFY_SCRIPT=/tmp/verify-helm-tarball.sh \
bash /tmp/install-helm-binary.sh \
&& rm -f /tmp/Makefile /tmp/artifacts.lock.yaml /tmp/install-helm-binary.sh /tmp/verify-helm-tarball.sh

# Stage 2b: Build helm from vendored source (use when no binary available in Stage 2a)
# Swap with Stage 2a: comment out Stage 2a, uncomment below, and use gomod prefetch instead of generic.
# update via: make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v<NEW>
# https://registry.access.redhat.com/ubi9/go-toolset
FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1786351949@sha256:0b471eb04868f3d9d90bf3c668f9c6c7a22cef07474ac9fec067909dfd7dec7c AS helm-builder
COPY Makefile /tmp/Makefile
COPY vendor/helm /opt/app-root/src/helm
WORKDIR /opt/app-root/src/helm
RUN HELM_VERSION=$(grep '^HELM_VERSION' /tmp/Makefile | sed 's/.*:= *//') && \
CGO_ENABLED=0 go build -trimpath \
-ldflags "-X helm.sh/helm/v4/internal/version.version=v${HELM_VERSION}" \
-o /tmp/helm ./cmd/helm && \
/tmp/helm version
# FROM registry.access.redhat.com/ubi9/go-toolset:9.8-1786351949@sha256:0b471eb04868f3d9d90bf3c668f9c6c7a22cef07474ac9fec067909dfd7dec7c AS helm-builder
# COPY Makefile /tmp/Makefile
# COPY vendor/helm /opt/app-root/src/helm
# WORKDIR /opt/app-root/src/helm
# RUN HELM_VERSION=$(grep '^HELM_VERSION' /tmp/Makefile | sed 's/.*:= *//') && \
# CGO_ENABLED=0 go build -mod=vendor -trimpath \
# -ldflags "-X helm.sh/helm/v4/internal/version.version=v${HELM_VERSION}" \
# -o /tmp/helm ./cmd/helm && \
# /tmp/helm version

# Stage 3: Final image
# https://registry.access.redhat.com/ubi9-minimal
Expand Down Expand Up @@ -81,7 +97,7 @@ RUN curl -L https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable-4.2
&& oc version --client \
&& kubectl version --client

# Copy helm binary built from source (vendor/helm)
# Copy helm binary from CGW mirror (helm-builder stage)
COPY --from=helm-builder /tmp/helm /usr/local/bin/helm

# Copy websocat binary built from source (vendor/websocat)
Expand Down
30 changes: 20 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ YQ_VERSION := 3.4.2
YQ_VENV := $(TOOLS_DIR)/yq-venv
YQ_BIN := $(YQ_VENV)/bin/yq

# Host platform (must be defined before HELM_ARCHIVE_DIR / WEBSOCAT_ARCH)
OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')

# latest at https://github.com/helm/helm/releases
# if version set below is available as a binary in CGW, update the helm-lockfile via: make helm-lockfile-update
# if version set below is not available as a binary in CGW, vendor the helm source via: make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v<NEW>
HELM_VERSION := 4.2.3
HELM_ARCHIVE_DIR := $(TOOLS_DIR)/helm-$(HELM_VERSION)
HELM_ARCHIVE_DIR := $(TOOLS_DIR)/helm-$(HELM_VERSION)-$(OS)-$(ARCH)
HELM_BIN_DL := $(HELM_ARCHIVE_DIR)/helm
HELM_BIN := $(TOOLS_DIR)/helm

Expand All @@ -46,8 +52,6 @@ WEBSOCAT_ARCHIVE_DIR := $(TOOLS_DIR)/websocat-$(WEBSOCAT_VERSION)
WEBSOCAT_BIN_DL := $(WEBSOCAT_ARCHIVE_DIR)/websocat
WEBSOCAT_BIN := $(TOOLS_DIR)/websocat

OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
# websocat uses different naming: x86_64-unknown-linux-musl, x86_64-apple-darwin, aarch64-apple-darwin
# Note: Apple Silicon returns 'arm64' but websocat uses 'aarch64'
WEBSOCAT_ARCH := $(shell uname -m | sed 's/arm64/aarch64/')-$(if $(filter darwin,$(OS)),apple-darwin,unknown-linux-musl)
Expand Down Expand Up @@ -166,11 +170,7 @@ $(YQ_BIN): $(TOOLS_DIR)
$(HELM_BIN_DL): $(TOOLS_DIR)
@mkdir -p "$(HELM_ARCHIVE_DIR)"
@if [ ! -f "$(HELM_BIN_DL)" ]; then \
echo "Downloading helm v$(HELM_VERSION) for $(OS)-$(ARCH)..."; \
curl -sSL "https://get.helm.sh/helm-v$(HELM_VERSION)-$(OS)-$(ARCH).tar.gz" \
| tar xz -C "$(HELM_ARCHIVE_DIR)" --strip-components=1 "$(OS)-$(ARCH)/helm"; \
chmod +x "$(HELM_BIN_DL)"; \
echo "helm installed successfully: $$($(HELM_BIN_DL) version --short)"; \
./hack/install-helm-local.sh "$(HELM_VERSION)" "$(HELM_BIN_DL)" "$(OS)" "$(ARCH)"; \
else \
echo "helm $(HELM_VERSION) already installed: $(HELM_BIN_DL)"; \
fi
Expand All @@ -195,15 +195,25 @@ VENDOR_NAME ?= ## Vendor name for vendor-update (e.g., websocat)
VENDOR_VERSION ?= ## Vendor version for vendor-update (e.g., v1.14.1)

.PHONY: vendor
vendor: ## Sync all vendored Git subtrees to their declared versions
./hack/update-vendor.sh helm "v$(HELM_VERSION)"
vendor: ## Sync vendored sources; refresh Helm CGW lockfile or vendor helm source
@if ./hack/check-helm-binary-available.sh "$(HELM_VERSION)"; then \
./hack/update-helm-lockfile.sh "v$(HELM_VERSION)"; \
else \
echo "CGW mirror has no helm v$(HELM_VERSION) binaries; vendoring helm source instead..."; \
./hack/update-vendor.sh helm "v$(HELM_VERSION)"; \
fi
./hack/update-vendor.sh websocat "v$(WEBSOCAT_VERSION)"

.PHONY: helm-lockfile-update
helm-lockfile-update: ## Refresh artifacts.lock.yaml for Helm CGW binaries (HELM_VERSION from Makefile)
./hack/update-helm-lockfile.sh "v$(HELM_VERSION)"

.PHONY: vendor-update
vendor-update: ## Sync a single vendored subtree to a specific version (VENDOR_NAME, VENDOR_VERSION required)
@if [ -z "$(VENDOR_NAME)" ] || [ -z "$(VENDOR_VERSION)" ]; then \
echo "Error: VENDOR_NAME and VENDOR_VERSION are required."; \
echo "Usage: make vendor-update VENDOR_NAME=websocat VENDOR_VERSION=v1.14.1"; \
echo " make vendor-update VENDOR_NAME=helm VENDOR_VERSION=v4.2.3"; \
exit 1; \
fi
./hack/update-vendor.sh "$(VENDOR_NAME)" "$(VENDOR_VERSION)"
Expand Down
10 changes: 10 additions & 0 deletions artifacts.lock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
metadata:
version: "1.0"
artifacts:
- download_url: https://mirror.openshift.com/pub/cgw/helm/4.2.3/helm-linux-amd64.tar.gz
checksum: sha256:2e6ce9696a806be8f33ff538018a29e318b9409d46adac30089c0e07f70488ac
filename: helm-linux-amd64.tar.gz
- download_url: https://mirror.openshift.com/pub/cgw/helm/4.2.3/helm-linux-arm64.tar.gz
checksum: sha256:b1d40f3ee91ed837c46281e66001fdc16cc7ca96c9a232d809a787438c08fe19
filename: helm-linux-arm64.tar.gz
47 changes: 47 additions & 0 deletions hack/check-helm-binary-available.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
#
# Return 0 when Helm CGW mirror artifacts exist for the requested scope.
#
# Usage:
# hack/check-helm-binary-available.sh <version> # linux amd64 + arm64 (Konflux lockfile)
# hack/check-helm-binary-available.sh <version> <os> <arch> # single platform tarball (local Makefile)
#
# Examples:
# hack/check-helm-binary-available.sh 4.2.3
# hack/check-helm-binary-available.sh 4.2.3 darwin arm64

set -euo pipefail

if [[ $# -lt 1 || $# -gt 3 ]]; then
sed -n '2,/^$/s/^# \{0,1\}//p' "$0"
exit 2
fi

VERSION="${1#v}"
BASE_URL="https://mirror.openshift.com/pub/cgw/helm/${VERSION}"

if ! command -v curl &>/dev/null; then
echo "Error: curl is required" >&2
exit 2
fi

tarball_exists() {
local os="$1" arch="$2"
local url="${BASE_URL}/helm-${os}-${arch}.tar.gz"
local code
code="$(curl -fsIL -o /dev/null -w '%{http_code}' "${url}" 2>/dev/null || true)"
[[ "${code}" == "200" ]]
}

if [[ $# -eq 3 ]]; then
tarball_exists "$2" "$3"
exit $?
fi

checksums="$(curl -fsSL "${BASE_URL}/sha256sum.txt" 2>/dev/null || true)"
if [[ -z "${checksums}" ]]; then
exit 1
fi

grep -q ' helm-linux-amd64.tar.gz$' <<< "${checksums}" \
&& grep -q ' helm-linux-arm64.tar.gz$' <<< "${checksums}"
87 changes: 87 additions & 0 deletions hack/install-helm-binary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
#
# Install helm from a Red Hat CGW mirror binary tarball to /tmp/helm.
#
# Curl mode (upstream Containerfile helm-builder):
# HELM_VERSION=4.2.3 CONTAINER_BUILD=true TARGETPLATFORM=linux/arm64 \
# hack/install-helm-binary.sh
#
# Prefetch mode (Konflux hermetic helm-builder):
# CONTAINER_BUILD=true TARGETPLATFORM=linux/arm64 \
# hack/install-helm-binary.sh --prefetch
#
# Local Makefile uses OS/ARCH from the host (darwin or linux) without CONTAINER_BUILD.

set -euo pipefail

PREFETCH=false
if [[ "${1:-}" == "--prefetch" ]]; then
PREFETCH=true
fi

if [[ -n "${TARGETPLATFORM:-}" ]]; then
# Use field 2 so linux/arm64/v8 (BuildKit) yields arm64, not v8.
BUILD_OS="${TARGETPLATFORM%%/*}"
BUILD_ARCH="$(cut -d/ -f2 <<< "${TARGETPLATFORM}")"
else
BUILD_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$(uname -m)" in
x86_64) BUILD_ARCH=amd64 ;;
aarch64|arm64) BUILD_ARCH=arm64 ;;
*) echo "unsupported arch: $(uname -m)" >&2; exit 1 ;;
esac
fi

if [[ "${CONTAINER_BUILD:-}" == "true" ]]; then
case "${BUILD_OS}" in
linux) ;;
*) echo "unsupported OS for container image: ${BUILD_OS} (expected linux)" >&2; exit 1 ;;
esac
fi

case "${BUILD_ARCH}" in
amd64|arm64) ;;
*) echo "unsupported arch: ${BUILD_ARCH}" >&2; exit 1 ;;
esac

TARBALL="helm-${BUILD_OS}-${BUILD_ARCH}.tar.gz"
MEMBER="helm-${BUILD_OS}-${BUILD_ARCH}"

extract_helm() {
local archive="$1"
tar xzf "${archive}" -C /tmp "${MEMBER}"
mv "/tmp/${MEMBER}" /tmp/helm
}

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERIFY_SCRIPT="${VERIFY_SCRIPT:-${SCRIPT_DIR}/verify-helm-tarball.sh}"

if ${PREFETCH}; then
# shellcheck disable=SC1091
. /cachi2/cachi2.env
extract_helm "/cachi2/output/deps/generic/${TARBALL}"
else
if [[ -z "${HELM_VERSION:-}" ]]; then
echo "HELM_VERSION is required for curl mode" >&2
exit 1
fi
curl -fsSL "https://mirror.openshift.com/pub/cgw/helm/${HELM_VERSION}/${TARBALL}" \
Comment thread
nickboldt marked this conversation as resolved.
-o "/tmp/${TARBALL}"
if [[ -z "${LOCKFILE:-}" ]]; then
if [[ -f "${SCRIPT_DIR}/artifacts.lock.yaml" ]]; then
LOCKFILE="${SCRIPT_DIR}/artifacts.lock.yaml"
else
LOCKFILE="${SCRIPT_DIR}/../artifacts.lock.yaml"
fi
fi
if [[ ! -f "${VERIFY_SCRIPT}" ]]; then
echo "Error: verify script not found: ${VERIFY_SCRIPT}" >&2
exit 1
fi
bash "${VERIFY_SCRIPT}" "/tmp/${TARBALL}" "${TARBALL}" "${LOCKFILE}" "${HELM_VERSION}"
extract_helm "/tmp/${TARBALL}"
rm -f "/tmp/${TARBALL}"
Comment thread
nickboldt marked this conversation as resolved.
fi

chmod +x /tmp/helm
/tmp/helm version
Loading
Loading