Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,18 @@ jobs:
for f in dist/helm-diff-*.tgz; do
echo "== $f =="
tar tzf "$f"
for member in diff/plugin.yaml diff/install-binary.sh diff/install-binary.ps1; do
# Archives are wrapped in a directory named after the archive
# itself (required by helm 4 installs from a tarball, see #1071)
base="$(basename "$f" .tgz)"
for member in "$base/plugin.yaml" "$base/install-binary.sh" "$base/install-binary.ps1"; do
if ! tar tzf "$f" | grep -q "^${member}$"; then
echo "ERROR: ${member} missing from ${f}"
missing=1
fi
done
# the binary has a .exe suffix on windows archives
if ! tar tzf "$f" | grep -qE '^diff/bin/diff(\.exe)?$'; then
echo "ERROR: diff/bin/diff missing from ${f}"
if ! tar tzf "$f" | grep -qE "^${base}/bin/diff(\\.exe)?$"; then
echo "ERROR: ${base}/bin/diff missing from ${f}"
missing=1
fi
done
Expand All @@ -107,9 +110,9 @@ jobs:
mkdir -p /tmp/archive-test
tar xzf dist/helm-diff-linux-amd64.tgz -C /tmp/archive-test
echo "Extracted archive layout:"
find /tmp/archive-test/diff -maxdepth 2 -type f | sort
find /tmp/archive-test/helm-diff-linux-amd64 -maxdepth 2 -type f | sort

out="$(helm plugin install /tmp/archive-test/diff 2>&1)"
out="$(helm plugin install /tmp/archive-test/helm-diff-linux-amd64 2>&1)"
echo "$out"
# The install hook must find the bundled binary already staged in
# HELM_PLUGIN_DIR and skip the network download.
Expand All @@ -120,6 +123,43 @@ jobs:
}
helm diff version
echo "End-to-end archive install test passed: installed from archive without downloading"
-
name: Set up Helm 4
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: azure/setup-helm@v5
with:
version: v4.3.0
-
# Regression test for issue #1071: helm 4 must be able to install
# directly from a local tarball (which it verifies by default), so
# archives must be wrapped in a directory named after the tarball.
name: Helm 4 offline tarball install test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
env:
HELM_DATA_HOME: /tmp/helm4-data
run: |
set -e
archive="dist/helm-diff-linux-amd64.tgz"

export GNUPGHOME="$(mktemp -d)"
chmod 700 "$GNUPGHOME"
gpg --batch --pinentry-mode loopback --passphrase '' \
--quick-generate-key "helm-diff-test" rsa3072 sign 0
GPG_FINGERPRINT=$(gpg --batch --with-colons --list-secret-keys "helm-diff-test" \
| grep '^fpr:' | head -1 | cut -d: -f10)
export GPG_FINGERPRINT GPG_PASSPHRASE=""

./scripts/sign-provenance.sh "$archive" "$archive.prov"
gpg --export --armor "helm-diff-test" > /tmp/keyring.gpg

out="$(helm plugin install "$archive" --keyring /tmp/keyring.gpg 2>&1)"
echo "$out"
echo "$out" | grep -q "Plugin Hash Verified" || {
echo "ERROR: helm 4 did not verify the signed archive."
exit 1
}
helm diff version
echo "Helm 4 offline tarball install test passed: installed and verified from a local tarball"
-
name: Export and upload public key
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
Expand Down
7 changes: 6 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ archives:
- linux-additional
format: tgz
name_template: '{{ .ProjectName }}-{{ if eq .Os "darwin" }}macos{{ else }}{{ .Os }}{{ end }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
wrap_in_directory: diff
# Wrap archives in a directory named after the archive itself
# (e.g. helm-diff-linux-amd64/). Helm 4's plugin installer requires this
# when installing from a local tarball: it derives the expected directory
# from the tarball filename and fails with "plugin.yaml not found in
# expected directory" otherwise (see issue #1071).
wrap_in_directory: true
files:
- README.md
- plugin.yaml
Expand Down
54 changes: 30 additions & 24 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,34 +68,40 @@ docker-run-release:
-v $(shell pwd)/docker-run-release-cache:/.cache \
-w $(pkg) helm-diff-release make release

# dist-package builds the plugin for a single platform and packs it into
# release/$(1).tgz. The archive content is wrapped in a directory named
# after the archive itself (e.g. helm-diff-linux-amd64/). Helm 4's plugin
# installer requires this when installing directly from a tarball: it
# derives the expected directory from the tarball filename and fails with
# "plugin.yaml not found in expected directory" otherwise (see issue #1071).
# Usage: $(call dist-package,<platform>,<GOOS>,<GOARCH>[,<extra env>])
DIST_PACKAGE_FILES := README.md LICENSE plugin.yaml install-binary.sh install-binary.ps1
define dist-package
mkdir -p build/helm-diff-$(1)/bin
cp $(DIST_PACKAGE_FILES) build/helm-diff-$(1)/
goarch=$(3); bin=diff; [ "$(2)" = "windows" ] && bin=$$bin.exe; \
$(4) GOOS=$(2) GOARCH=$$goarch $(GO) build -o build/helm-diff-$(1)/bin/$$bin -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-$(1).tgz helm-diff-$(1)/
rm -rf build/helm-diff-$(1)

endef

.PHONY: dist
dist: export COPYFILE_DISABLE=1 #teach OSX tar to not put ._* files in tar archive
dist: export CGO_ENABLED=0
dist:
rm -rf build/diff/* release/*
mkdir -p build/diff/bin release/
cp README.md LICENSE plugin.yaml build/diff
GOOS=linux GOARCH=amd64 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-amd64.tgz diff/
GOOS=linux GOARCH=arm64 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-arm64.tgz diff/
GOOS=linux GOARCH=arm GOARM=6 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-armv6.tgz diff/
GOOS=linux GOARCH=arm GOARM=7 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-armv7.tgz diff/
GOOS=linux GOARCH=ppc64le $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-ppc64le.tgz diff/
GOOS=linux GOARCH=s390x $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-linux-s390x.tgz diff/
GOOS=freebsd GOARCH=amd64 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-freebsd-amd64.tgz diff/
GOOS=darwin GOARCH=amd64 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-macos-amd64.tgz diff/
GOOS=darwin GOARCH=arm64 $(GO) build -o build/diff/bin/diff -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-macos-arm64.tgz diff/
rm build/diff/bin/diff
GOOS=windows GOARCH=amd64 $(GO) build -o build/diff/bin/diff.exe -trimpath -ldflags="$(LDFLAGS)"
tar -C build/ -zcvf $(CURDIR)/release/helm-diff-windows-amd64.tgz diff/
rm -rf build/ release/*
mkdir -p release/
$(call dist-package,linux-amd64,linux,amd64)
$(call dist-package,linux-arm64,linux,arm64)
$(call dist-package,linux-armv6,linux,arm,GOARM=6)
$(call dist-package,linux-armv7,linux,arm,GOARM=7)
$(call dist-package,linux-ppc64le,linux,ppc64le)
$(call dist-package,linux-s390x,linux,s390x)
$(call dist-package,freebsd-amd64,freebsd,amd64)
$(call dist-package,macos-amd64,darwin,amd64)
$(call dist-package,macos-arm64,darwin,arm64)
$(call dist-package,windows-amd64,windows,amd64)

.PHONY: release
release: lint dist
Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ helm plugin install https://github.com/databus23/helm-diff

If installing this in an offline/airgapped environment, download the platform-specific binary archive (e.g., `helm-diff-linux-amd64.tgz` or `helm-diff-windows-amd64.tgz`) from [releases](https://github.com/databus23/helm-diff/releases). Make sure to select the correct `.tgz` file for your operating system and architecture.

The release archives include everything needed to install the plugin (binary, `plugin.yaml`, and the install scripts). The simplest way to install offline is to extract the archive and point `helm plugin install` at the extracted directory:
The release archives include everything needed to install the plugin (binary, `plugin.yaml`, and the install scripts). Each archive wraps its content in a directory named after the archive itself (e.g. `helm-diff-linux-amd64/`), which is what Helm 4 expects when installing from a tarball.

The simplest way to install offline is to extract the archive and point `helm plugin install` at the extracted directory:

```
tar xzf helm-diff-linux-amd64.tgz # extracts into a ./diff directory
helm plugin install ./diff
tar xzf helm-diff-linux-amd64.tgz # extracts into a ./helm-diff-linux-amd64 directory
helm plugin install ./helm-diff-linux-amd64
```

The install script detects that the binary is already bundled and skips the GitHub download.
Expand Down Expand Up @@ -63,6 +65,16 @@ gpg --list-keys --with-fingerprint EA17A2A206AFF8CD
helm plugin install https://github.com/databus23/helm-diff/releases/latest/download/helm-diff-linux-amd64.tgz
```

For offline/airgapped environments with Helm 4, transfer the release tarball **together with its `.prov` file** (and keep the original tarball file name — provenance verification matches the file name against the checksums recorded in the `.prov` file) and install directly from the tarball:

```shell
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/helm-diff-linux-amd64.tgz
curl -LO https://github.com/databus23/helm-diff/releases/download/<TAG>/helm-diff-linux-amd64.tgz.prov
helm plugin install helm-diff-linux-amd64.tgz --keyring <path-to-keyring.gpg>
```

(Replace `<TAG>` with the release you are installing. The direct tarball install requires Helm 4. On Helm 3, extract the archive and install from the extracted directory as described above.)

For offline/airgapped environments, download the public key from the maintainer's GitHub profile on a connected machine, transfer it, and import it locally:

```shell
Expand All @@ -82,11 +94,12 @@ For more information about Helm 4's plugin verification, see:
### Pre Helm 2.3.0 Installation
Pick a release tarball from the [releases](https://github.com/databus23/helm-diff/releases) page.

Unpack the tarball in your helm plugins directory (`$(helm home)/plugins`).
Unpack the tarball in your helm plugins directory (`$(helm home)/plugins`) into a `diff` directory.

E.g.
```
curl -L $TARBALL_URL | tar -C $(helm home)/plugins -xzv
mkdir -p $(helm home)/plugins/diff
curl -L $TARBALL_URL | tar -C $(helm home)/plugins/diff --strip-components=1 -xzv
```

### From Source
Expand Down
22 changes: 19 additions & 3 deletions install-binary.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,28 @@ function Install-Plugin {
tar -xzf $ArchiveName -C .
Pop-Location
New-Item -ItemType Directory -Path $Destination -Force
Copy-Item -Path (Join-Path $ArchiveDirectory "diff" "bin" "diff.exe") -Destination $Destination -Force
# Release archives wrap their content in a directory named after the
# archive itself (e.g. helm-diff-windows-amd64/bin/diff.exe), as required
# by helm 4 when installing directly from a tarball (issue #1071).
# Archives from earlier releases wrap the content in a
# directory named "diff" instead.
$wrapDir = [System.IO.Path]::GetFileNameWithoutExtension($ArchiveName)
$binary = Join-Path $ArchiveDirectory $wrapDir "bin" "diff.exe"
if (-not (Test-Path $binary -PathType Leaf)) {
$binary = Join-Path $ArchiveDirectory "diff" "bin" "diff.exe"
}
Copy-Item -Path $binary -Destination $Destination -Force
}

$ErrorActionPreference = "Stop"

$archiveName = "helm-diff.tgz"
$arch = Get-Architecture

# Archives wrap their content in a directory named after the archive
# itself (see Install-Plugin below), so the temporary copy must keep the
# original file name.
$archiveName = "helm-diff-windows-${arch}.tgz"

# If installing (not updating) and the binary is already staged in the
# plugin dir (e.g. installing from a release archive that bundles the
# correct platform binary), skip the redundant download. Update mode
Expand All @@ -84,18 +98,20 @@ if (-not $Update -and (Test-Path $pluginBin -PathType Leaf)) {

$tmpDir = New-TemporaryDirectory
trap { Remove-Item -path $tmpDir -Recurse -Force }
$output = Join-Path $tmpDir $archiveName

# Check for offline installation via environment variable
if ($env:HELM_DIFF_BIN_TGZ) {
Write-Host "HELM_DIFF_BIN_TGZ is set. Using local package at: $($env:HELM_DIFF_BIN_TGZ)"
if (-not (Test-Path $env:HELM_DIFF_BIN_TGZ -PathType Leaf)) {
throw "Offline installation failed: File not found at '$($env:HELM_DIFF_BIN_TGZ)'"
}
$archiveName = [System.IO.Path]::GetFileName($env:HELM_DIFF_BIN_TGZ)
$output = Join-Path $tmpDir $archiveName
Copy-Item -Path $env:HELM_DIFF_BIN_TGZ -Destination $output
}
else {
# Proceed with online installation
$output = Join-Path $tmpDir $archiveName
$version = Get-Version -Update $Update
$url = Get-Url -Version $version -Architecture $arch
Download-Plugin -Url $url -Output $output
Expand Down
23 changes: 17 additions & 6 deletions install-binary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,21 @@ rmTempDir() {
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
PLUGIN_TMP_FILE="${HELM_TMP}/${PROJECT_NAME}.tgz"

# If HELM_DIFF_BIN_TGZ is set, copy the local file instead of downloading
# If HELM_DIFF_BIN_TGZ is set, copy the local file instead of downloading.
# Keep its original file name: release archives wrap their content in a
# directory named after the archive (see installFile below).
if [ -n "$HELM_DIFF_BIN_TGZ" ]; then
echo "Using local package at $HELM_DIFF_BIN_TGZ"
if [ ! -f "$HELM_DIFF_BIN_TGZ" ]; then
echo "Error: file not found at $HELM_DIFF_BIN_TGZ"
exit 1
fi
PLUGIN_TMP_FILE="${HELM_TMP}/$(basename "$HELM_DIFF_BIN_TGZ")"
cp "$HELM_DIFF_BIN_TGZ" "$PLUGIN_TMP_FILE"
return
fi

PLUGIN_TMP_FILE="${HELM_TMP}/helm-diff-${OS}-${ARCH}.tgz"
echo "Downloading $DOWNLOAD_URL"
# Retry with backoff to absorb transient failures, e.g. a release window
# where the "latest" asset is already published but not fully uploaded yet.
Expand Down Expand Up @@ -155,11 +157,20 @@ downloadFile() {

# Unpack the archive file, then install it into the helm directory.
installFile() {
PLUGIN_TMP_FILE="${HELM_TMP}/${PROJECT_NAME}.tgz"
tar xzf "$PLUGIN_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/diff/bin/diff"
bin="diff"
if [ "${OS}" = "windows" ]; then
HELM_TMP_BIN="$HELM_TMP_BIN.exe"
bin="$bin.exe"
fi
# Release archives wrap their content in a directory named after the
# archive itself (e.g. helm-diff-linux-amd64/bin/diff), as required by
# helm 4 when installing directly from a tarball (issue #1071).
# Archives from earlier releases wrap the content in a directory named
# "diff" instead.
wrap_dir="$(basename "$PLUGIN_TMP_FILE" .tgz)"
HELM_TMP_BIN="$HELM_TMP/$wrap_dir/bin/$bin"
if [ ! -f "$HELM_TMP_BIN" ] && [ -f "$HELM_TMP/diff/bin/$bin" ]; then
HELM_TMP_BIN="$HELM_TMP/diff/bin/$bin"
fi
echo "Preparing to install into ${HELM_PLUGIN_DIR}"
mkdir -p "$HELM_PLUGIN_DIR/bin"
Expand Down