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
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,35 @@ jobs:
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Stamp plugin version
run: |
version="${GITHUB_REF_NAME#v}"
sed -i "s/^version:.*/version: \"${version}\"/" plugin.yaml
echo "Stamped plugin.yaml version: ${version}"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Sign plugin archives
if: ${{ vars.HELM_SCRIBE_SIGNING_ENABLED == 'true' }}
env:
HELM_SCRIBE_SIGNING_KEY: ${{ secrets.HELM_SCRIBE_SIGNING_KEY }}
HELM_SCRIBE_SIGNING_KEY_ID: ${{ secrets.HELM_SCRIBE_SIGNING_KEY_ID }}
run: |
set -euo pipefail
echo "$HELM_SCRIBE_SIGNING_KEY" | gpg --batch --import
version="${GITHUB_REF_NAME#v}"
./scripts/sign-plugin.sh "$version" dist
- name: Upload provenance files
if: ${{ vars.HELM_SCRIBE_SIGNING_ENABLED == 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
gh release upload "${GITHUB_REF_NAME}" dist/*.prov --clobber
- name: Summary
run: |
tag="${GITHUB_REF_NAME}"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ go.work.sum
helm-scribe
docs/
.test-fixture/
.signing-key-id
.signing-private-key.asc
9 changes: 9 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ archives:
formats: [zip]
name_template: >-
{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
files:
- plugin.yaml
- scripts/install-binary.sh
- scripts/install-binary.ps1
- README.md
- LICENSE

checksum:
name_template: checksums.txt

changelog:
sort: asc
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ Or, if you wish to install with go:
go install github.com/miosp/helm-scribe@latest
```

### As a Helm plugin

Install as a Helm plugin and run it as `helm scribe`:

```sh
# Helm v3 or v4 (git sources cannot be signature-verified)
helm plugin install https://github.com/Miosp/helm-scribe --verify=false
```

For a verified install on Helm v4 (from a release tarball), import the signing
key first, then point `helm plugin install` at a release archive:

```sh
curl -fsSL https://raw.githubusercontent.com/Miosp/helm-scribe/main/signing-key.asc \
| gpg --dearmor > helm-scribe-keyring.gpg
helm plugin install \
https://github.com/Miosp/helm-scribe/releases/download/v0.3.1/helm-scribe_v0.3.1_linux_amd64.tar.gz \
--verify
```

Then run `helm scribe` in any chart directory.

## Add README markers

Insert these where the parameters table should appear:
Expand Down
28 changes: 28 additions & 0 deletions plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "scribe"
# Auto-stamped from the release tag by the Release workflow; not load-bearing
# for installs (the install hooks resolve the latest release themselves).
version: "0.0.0"
usage: "generate a Helm values schema and README parameters table"
description: "Generate a values.schema.json and README parameters table from annotated values.yaml"
platformCommand:
- os: linux
command: $HELM_PLUGIN_DIR/bin/helm-scribe
- os: darwin
command: $HELM_PLUGIN_DIR/bin/helm-scribe
- os: windows
command: $HELM_PLUGIN_DIR/bin/helm-scribe.exe
platformHooks:
install:
- os: linux
command: $HELM_PLUGIN_DIR/scripts/install-binary.sh
- os: darwin
command: $HELM_PLUGIN_DIR/scripts/install-binary.sh
- os: windows
command: powershell -ExecutionPolicy Bypass -File $HELM_PLUGIN_DIR/scripts/install-binary.ps1
update:
- os: linux
command: $HELM_PLUGIN_DIR/scripts/install-binary.sh
- os: darwin
command: $HELM_PLUGIN_DIR/scripts/install-binary.sh
- os: windows
command: powershell -ExecutionPolicy Bypass -File $HELM_PLUGIN_DIR/scripts/install-binary.ps1
91 changes: 91 additions & 0 deletions scripts/install-binary.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Download and install the helm-scribe binary into the Helm plugin directory.
# Invoked by Helm as the plugin install/update hook on Windows.
# Targets Windows PowerShell 5.1 (built into Windows) and PowerShell 7+.
#Requires -Version 5.1

$ErrorActionPreference = "Stop"

$ProjectName = "helm-scribe"
$ProjectGh = "Miosp/$ProjectName"

$PluginDir = $env:HELM_PLUGIN_DIR
if (-not $PluginDir) { throw "HELM_PLUGIN_DIR is not set." }

# GitHub requires TLS 1.2.
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12

# Resolve the latest release tag via GitHub's /releases/latest redirect (no API,
# no rate limit). AllowAutoRedirect=$false makes GetResponse throw on the 302;
# the redirect Location lives on the exception's response.
function Resolve-LatestTag {
$req = [System.Net.HttpWebRequest]::Create("https://github.com/$ProjectGh/releases/latest")
$req.AllowAutoRedirect = $false
try {
$resp = $req.GetResponse()
} catch [System.Net.WebException] {
$resp = $_.Exception.Response
}
if (-not $resp) { throw "Could not resolve the latest release tag for $ProjectGh." }
$location = $resp.Headers["Location"]
$resp.Close()
if (-not $location) { throw "Could not resolve the latest release tag for $ProjectGh." }
return ($location -split '/')[-1]
}

# Map the Windows architecture to the goreleaser arch name we publish.
switch ($env:PROCESSOR_ARCHITECTURE) {
"AMD64" { $arch = "amd64" }
"ARM64" { $arch = "arm64" }
default { throw "Architecture '$env:PROCESSOR_ARCHITECTURE' is not supported." }
}

$tag = Resolve-LatestTag
$version = $tag -replace '^v', ''
$archive = "${ProjectName}_${version}_windows_${arch}.zip"
$base = "https://github.com/$ProjectGh/releases/download/$tag"
$downloadUrl = "$base/$archive"
$checksumUrl = "$base/checksums.txt"

$tmp = Join-Path ([System.IO.Path]::GetTempPath()) "helm-scribe-install-$([System.Guid]::NewGuid())"
New-Item -ItemType Directory -Path $tmp -Force | Out-Null
try {
$zip = Join-Path $tmp $archive
Write-Host "Downloading $downloadUrl"
Invoke-WebRequest -Uri $downloadUrl -OutFile $zip -UseBasicParsing

# Checksum verification against checksums.txt (best-effort; older releases
# may not ship one).
try {
$checksums = (Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing).Content
$expected = $null
foreach ($line in ($checksums -split "`n")) {
if ($line -match "\s$([regex]::Escape($archive))\s*$") {
$expected = ($line -split '\s+')[0]
break
}
}
if ($expected) {
$actual = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $expected.ToLower()) {
throw "Checksum mismatch for $archive.`n expected: $expected`n actual: $actual"
}
} else {
Write-Warning "$archive not found in checksums.txt; skipping verification."
}
} catch {
Write-Warning "Could not download checksums.txt; skipping verification."
}

# Extract and install the binary.
Expand-Archive -Path $zip -DestinationPath $tmp -Force
$binDir = Join-Path $PluginDir "bin"
New-Item -ItemType Directory -Path $binDir -Force | Out-Null
$exe = Join-Path $tmp "$ProjectName.exe"
if (-not (Test-Path $exe)) { throw "Binary $ProjectName.exe not found in the archive." }
Move-Item -Force $exe (Join-Path $binDir "$ProjectName.exe")

Write-Host "$ProjectName installed into $binDir\$ProjectName.exe"
Write-Host "Run 'helm scribe --help' to get started."
} finally {
Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
}
183 changes: 183 additions & 0 deletions scripts/install-binary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/bin/sh
# Download and install the helm-scribe binary into the Helm plugin directory.
# Invoked by Helm as the plugin install/update hook.
#
# Adapted from the helm-template / helm-schema plugin installers.

set -eu

PROJECT_NAME="helm-scribe"
BINARY_NAME="helm-scribe"
PROJECT_GH="Miosp/$PROJECT_NAME"
BIN_DIR_SUFFIX="bin"

# Convert HELM_BIN and HELM_PLUGIN_DIR to unix paths when running under
# MSYS2/Cygwin on Windows, where helm returns Windows paths.
if command -v cygpath >/dev/null 2>&1; then
HELM_BIN="$(cygpath -u "${HELM_BIN}")"
HELM_PLUGIN_DIR="$(cygpath -u "${HELM_PLUGIN_DIR}")"
fi

[ -z "$HELM_BIN" ] && HELM_BIN="$(command -v helm || true)"

if [ "${SKIP_BIN_INSTALL:-}" = "1" ]; then
echo "Skipping binary install"
exit 0
fi

# Helm passes -u for updates. Both install and update resolve the latest
# release tag, so plugin.yaml's version field is never load-bearing here.

# initArch maps uname -m to the goreleaser arch names we publish.
initArch() {
ARCH="$(uname -m)"
case "$ARCH" in
x86_64|amd64) ARCH="amd64" ;;
aarch64|arm64) ARCH="arm64" ;;
*)
echo "Architecture '$(uname -m)' is not supported." >&2
exit 1
;;
esac
}

# initOS maps uname -s to the lowercase goreleaser os names we publish.
initOS() {
OS="$(uname -s)"
case "$OS" in
Windows_NT|MSYS*|MINGW*|CYGWIN*) OS="windows" ;;
Darwin) OS="darwin" ;;
Linux) OS="linux" ;;
*)
echo "OS '$(uname)' is not supported." >&2
exit 1
;;
esac
}

# verifySupported rejects unsupported os/arch combos and requires a downloader.
verifySupported() {
supported="linux-amd64
linux-arm64
darwin-amd64
darwin-arm64
windows-amd64
windows-arm64"
if ! echo "$supported" | grep -q "^${OS}-${ARCH}$"; then
echo "No prebuilt binary for ${OS}-${ARCH}." >&2
exit 1
fi
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
echo "Either curl or wget is required." >&2
exit 1
fi
}

# downloadFile fetches a URL to stdout.
downloadFile() {
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$1"
else
wget -qO- "$1"
fi
}

# resolveLatestTag returns the latest release tag (e.g. v0.3.1) by following
# GitHub's /releases/latest redirect. No API call, so no rate limit.
resolveLatestTag() {
url="https://github.com/${PROJECT_GH}/releases/latest"
if command -v curl >/dev/null 2>&1; then
headers="$(curl -fsSI "$url" 2>/dev/null || true)"
else
headers="$(wget -Sq --spider "$url" 2>&1 >/dev/null || true)"
fi
echo "$headers" | tr -d '\r' | awk 'tolower($1)=="location:"{print $2}' | sed 's:.*/tag/::; s:.*/::'
}

# getDownloadURL sets DOWNLOAD_URL and CHECKSUM_URL against the latest release.
# Release tags are v-prefixed (e.g. v0.3.1); archive filenames use the bare
# version (e.g. helm-scribe_0.3.1_linux_amd64.tar.gz).
getDownloadURL() {
ext="tar.gz"
if [ "$OS" = "windows" ]; then
ext="zip"
fi
version="$(resolveLatestTag)"
version="${version#v}"
if [ -z "$version" ]; then
echo "Could not resolve the latest release tag for ${PROJECT_GH}." >&2
exit 1
fi
tag="v${version}"
archive="${PROJECT_NAME}_${version}_${OS}_${ARCH}.${ext}"
base="https://github.com/${PROJECT_GH}/releases"
DOWNLOAD_URL="${base}/download/${tag}/${archive}"
CHECKSUM_URL="${base}/download/${tag}/checksums.txt"
}

mkTempDir() {
HELM_TMP="$(mktemp -d 2>/dev/null || mktemp -d -t "${PROJECT_NAME}-XXXXXX")"
}

rmTempDir() {
if [ -n "${HELM_TMP:-}" ] && [ -d "$HELM_TMP" ]; then
rm -rf "$HELM_TMP"
fi
}

# extractFile extracts the downloaded archive into the plugin bin dir.
extractFile() {
bin_dir="${HELM_PLUGIN_DIR}/${BIN_DIR_SUFFIX}"
mkdir -p "$bin_dir"
archive="$(basename "$DOWNLOAD_URL")"
if [ "$OS" = "windows" ]; then
unzip -o "$HELM_TMP/$archive" -d "$HELM_TMP/unpacked" >/dev/null
mv "$HELM_TMP/unpacked/${BINARY_NAME}.exe" "${bin_dir}/${BINARY_NAME}.exe" 2>/dev/null \
|| mv "$HELM_TMP/unpacked/${BINARY_NAME}" "${bin_dir}/${BINARY_NAME}.exe"
else
tar -xzf "$HELM_TMP/$archive" -C "$HELM_TMP"
mv "$HELM_TMP/${BINARY_NAME}" "${bin_dir}/${BINARY_NAME}"
chmod +x "${bin_dir}/${BINARY_NAME}"
fi
}

# verifyChecksum checks the archive hash against checksums.txt.
verifyChecksum() {
archive="$(basename "$DOWNLOAD_URL")"
checksums="$(downloadFile "$CHECKSUM_URL" || true)"
if [ -z "$checksums" ]; then
echo "Warning: could not download checksums.txt; skipping verification." >&2
return 0
fi
expected="$(echo "$checksums" | grep -E " ${archive}\$" | awk '{print $1}')"
if [ -z "$expected" ]; then
echo "Warning: ${archive} not found in checksums.txt; skipping verification." >&2
return 0
fi
actual="$(sha256sum "$HELM_TMP/$archive" | awk '{print $1}')"
if [ "$actual" != "$expected" ]; then
echo "Checksum mismatch for ${archive}." >&2
echo " expected: ${expected}" >&2
echo " actual: ${actual}" >&2
rmTempDir
exit 1
fi
}

initArch
initOS
verifySupported
getDownloadURL

echo "Downloading ${DOWNLOAD_URL}"
mkTempDir
trap rmTempDir EXIT

archive="$(basename "$DOWNLOAD_URL")"
downloadFile "$DOWNLOAD_URL" > "$HELM_TMP/$archive"

verifyChecksum
extractFile

echo "$PROJECT_NAME installed into ${HELM_PLUGIN_DIR}/${BIN_DIR_SUFFIX}/${BINARY_NAME}"
echo "Run 'helm scribe --help' to get started."
Loading
Loading