-
Notifications
You must be signed in to change notification settings - Fork 9
feat(ci): release & distribution pipeline — ADR 0003 + scaffold workflow #405
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
e7a431c
docs(adr): add ADR 0003 — release & distribution CI/CD
Matovidlo 2b7a6af
feat(ci): native-binary release & distribution pipeline (PyInstaller …
Matovidlo 16765c5
ci(release): scope GITHUB_TOKEN permissions per job (least privilege)
padak c10ab06
docs(adr): correct release ADR drift flagged in review (NB-2, NB-3, N…
padak 9e08ad7
ci(release): address review nits NIT-2/3/4 (supply-chain + fail-loud)
padak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| name: setup-build | ||
| description: Pin uv (and optionally Node 20) for kbagent build/release jobs. | ||
| inputs: | ||
| node: | ||
| description: Install Node 20 (needed for the React SPA build hook). | ||
| default: "true" | ||
| runs: | ||
| using: composite | ||
| steps: | ||
| - uses: astral-sh/setup-uv@v7 | ||
| with: | ||
| version: "0.11.16" | ||
| # Pin the interpreter explicitly (matches ci.yml / release.yml). Without it a job | ||
| # could run on whatever Python the runner ships, which may not satisfy >=3.12. | ||
| - uses: actions/setup-python@v6 | ||
| with: | ||
| python-version: "3.12" | ||
| - if: ${{ inputs.node == 'true' }} | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: "20" | ||
| package-manager-cache: false |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <!-- Chocolatey package for kbagent (id: keboola-cli2). Wraps the signed PyInstaller | ||
| .exe downloaded from cli-dist.keboola.com — no Python required. {VERSION} is | ||
| substituted by the release workflow. --> | ||
| <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> | ||
| <metadata> | ||
| <id>keboola-cli2</id> | ||
| <version>{VERSION}</version> | ||
| <title>Keboola Agent CLI (kbagent)</title> | ||
| <authors>Keboola</authors> | ||
| <projectUrl>https://github.com/keboola/cli</projectUrl> | ||
| <licenseUrl>https://github.com/keboola/cli/blob/main/LICENSE</licenseUrl> | ||
| <requireLicenseAcceptance>false</requireLicenseAcceptance> | ||
| <summary>AI-friendly CLI for managing Keboola projects.</summary> | ||
| <description>Self-contained native CLI for managing Keboola Connection projects. No Python runtime required.</description> | ||
| <tags>keboola cli kbagent</tags> | ||
| </metadata> | ||
| <files> | ||
| <file src="tools\**" target="tools" /> | ||
| </files> | ||
| </package> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Chocolatey install script for kbagent. Downloads the signed Windows .exe zip from | ||
| # cli-dist.keboola.com and shims `kbagent` onto PATH. {URL} and {CHECKSUM} are | ||
| # substituted by the release workflow. No Python runtime required. | ||
| $ErrorActionPreference = 'Stop' | ||
| $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" | ||
|
|
||
| $packageArgs = @{ | ||
| packageName = 'keboola-cli2' | ||
| unzipLocation = $toolsDir | ||
| url64bit = '{URL}' | ||
| checksum64 = '{CHECKSUM}' | ||
| checksumType64= 'sha256' | ||
| } | ||
|
|
||
| Install-ChocolateyZipPackage @packageArgs | ||
| # The extracted kbagent.exe in $toolsDir is auto-shimmed onto PATH by Chocolatey. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| """PyInstaller entry point for the frozen `kbagent` binary. | ||
|
|
||
| PyInstaller runs the entry script as top-level `__main__`, so the package's own | ||
| ``src/keboola_agent_cli/__main__.py`` (which uses a relative import | ||
| ``from .cli import app``) cannot be used directly — it raises | ||
| ``ImportError: attempted relative import with no known parent package``. | ||
|
|
||
| This launcher uses an absolute import instead. Verified to produce a working | ||
| no-Python binary (`env -i kbagent --version` → `kbagent vX.Y.Z`). | ||
| """ | ||
|
|
||
| from keboola_agent_cli.cli import app | ||
|
|
||
| app() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # Homebrew formula template for kbagent (package: keboola-cli2, binary: kbagent). | ||
| # The release workflow substitutes {VERSION} and the per-arch {SHA256_*} and pushes | ||
| # the rendered formula to the kbagent-owned tap repo `keboola/homebrew-keboola-cli2`. | ||
| # Wraps the prebuilt PyInstaller binary — no Python required on the user's machine. | ||
| class KeboolaCli2 < Formula | ||
| desc "AI-friendly CLI for managing Keboola projects (kbagent)" | ||
| homepage "https://github.com/keboola/cli" | ||
| version "{VERSION}" | ||
| license "MIT" | ||
|
|
||
| on_macos do | ||
| # Apple Silicon only (single macOS build env). Gate on arch so Intel Macs get a | ||
| # clear error instead of a broken arm64 binary. | ||
| on_arm do | ||
| url "https://cli-dist.keboola.com/keboola-cli2/v{VERSION}/keboola-cli2_{VERSION}_darwin_arm64.zip" | ||
| sha256 "{SHA256_DARWIN_ARM64}" | ||
| end | ||
| on_intel do | ||
| odie "keboola-cli2 ships Apple Silicon only on macOS. Install via: uv tool install keboola-cli" | ||
| end | ||
| end | ||
|
|
||
| on_linux do | ||
| on_arm do | ||
| url "https://cli-dist.keboola.com/keboola-cli2/v{VERSION}/keboola-cli2_{VERSION}_linux_arm64.zip" | ||
| sha256 "{SHA256_LINUX_ARM64}" | ||
| end | ||
| on_intel do | ||
| url "https://cli-dist.keboola.com/keboola-cli2/v{VERSION}/keboola-cli2_{VERSION}_linux_amd64.zip" | ||
| sha256 "{SHA256_LINUX_AMD64}" | ||
| end | ||
| end | ||
|
|
||
| def install | ||
| bin.install "kbagent" | ||
| end | ||
|
|
||
| test do | ||
| assert_match "kbagent v#{version}", shell_output("#{bin}/kbagent --version") | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #!/usr/bin/env bash | ||
| # Render the Homebrew formula from the template, substituting the version and the | ||
| # per-arch SHA256 sums (read from the *.sha256 sidecar files produced by `freeze`). | ||
| # Usage: render.sh <version> <artifacts-dir> (prints the formula to stdout) | ||
| set -euo pipefail | ||
| VERSION="$1" | ||
| ART="$2" | ||
| TMPL="$(dirname "$0")/keboola-cli2.rb.tmpl" | ||
|
|
||
| sha() { | ||
| # $1 = os, $2 = arch -> sha256 of keboola-cli2_<v>_<os>_<arch>.zip. | ||
| # Fail hard if the sidecar is missing — never render a formula with a bad checksum. | ||
| local f | ||
| f=$(find "$ART" -name "keboola-cli2_${VERSION}_$1_$2.zip.sha256" | head -1) | ||
| [ -n "$f" ] || { echo "::error::missing checksum for $1_$2 — refusing to render formula" >&2; exit 1; } | ||
| awk '{print $1}' "$f" | ||
| } | ||
|
|
||
| # Only the arches the template references (macOS arm64; Linux amd64 + arm64). | ||
| sed \ | ||
| -e "s/{VERSION}/${VERSION}/g" \ | ||
| -e "s/{SHA256_DARWIN_ARM64}/$(sha darwin arm64)/g" \ | ||
| -e "s/{SHA256_LINUX_ARM64}/$(sha linux arm64)/g" \ | ||
| -e "s/{SHA256_LINUX_AMD64}/$(sha linux amd64)/g" \ | ||
| "$TMPL" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #!/usr/bin/env bash | ||
| # Build deb/rpm/apk for each Linux arch from the frozen binaries, using nfpm. | ||
| # nfpm does not reliably expand ${...} in its config, so we render it with envsubst. | ||
| # Usage: build_packages.sh <version> [artifacts-dir] | ||
| set -euo pipefail | ||
| VERSION="$1" | ||
| ART="${2:-artifacts}" | ||
|
|
||
| command -v envsubst >/dev/null 2>&1 || { sudo apt-get update && sudo apt-get install -y gettext-base; } | ||
| mkdir -p dist | ||
|
|
||
| for arch in amd64 arm64; do | ||
| BIN="$ART/bin-linux-${arch}/kbagent" | ||
| [ -f "$BIN" ] || BIN="$ART/bin-linux-${arch}/dist/kbagent" # tolerate either download layout | ||
| [ -f "$BIN" ] || { echo "missing kbagent for $arch"; ls -R "$ART/bin-linux-${arch}"; exit 1; } | ||
| chmod +x "$BIN" | ||
|
|
||
| export VERSION PKG_ARCH="$arch" BIN_PATH="$BIN" | ||
| envsubst '${VERSION} ${PKG_ARCH} ${BIN_PATH}' < build/package/nfpm.yaml > /tmp/nfpm.yaml | ||
| for fmt in deb rpm apk; do | ||
| nfpm package -f /tmp/nfpm.yaml -p "$fmt" -t "dist/keboola-cli2_${VERSION}_linux_${arch}.${fmt}" | ||
| done | ||
| done | ||
| ls -al dist/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| #!/usr/bin/env bash | ||
| # Build/refresh the SIGNED apt(deb), yum(rpm) and apk repositories on the CLI dist | ||
| # S3 bucket so `apt-get install keboola-cli2` (etc.) works out of the box. | ||
| # | ||
| # Signing keys (separate per format): | ||
| # DEB_KEY_PRIVATE — GPG, signs the apt repo. The public keyring apt downloads is | ||
| # derived from it (dearmored binary), so there's no DEB_KEY_PUBLIC. | ||
| # RPM_KEY_PUBLIC — public half of the SEPARATE rpm signing key (nfpm signs the rpm | ||
| # packages with RPM_KEY_PRIVATE); published for yum clients. | ||
| # APK_KEY_PRIVATE / APK_KEY_PUBLIC — abuild RSA keypair, signs the apk index | ||
| # Requires AWS creds already configured (OIDC). | ||
| # Usage: index.sh <s3-bucket> <prefix> → s3://<bucket>/<prefix>/{deb,rpm,apk}/ | ||
| set -euo pipefail | ||
| BUCKET="$1" | ||
| PREFIX="$2" | ||
| WORK=$(mktemp -d) | ||
| trap 'rm -rf "$WORK"' EXIT # clean up temp dir + any key material on exit/failure | ||
|
|
||
| if [ -z "${DEB_KEY_PRIVATE:-}" ]; then | ||
| # publish-s3 only runs on real (non-pre-release) tags, where the repo + key must | ||
| # exist for the downstream test-install job. Fail loudly rather than silently | ||
| # skipping and leaving test-install to fail with an obscure root cause. | ||
| echo "::error::DEB_KEY_PRIVATE not set — cannot sign/index the apt repo for a real release." | ||
| exit 1 | ||
| fi | ||
|
|
||
| sudo apt-get update -y | ||
| # apk-tools + abuild are needed for the apk repo index; tolerate their absence. | ||
| sudo apt-get install -y dpkg-dev apt-utils createrepo-c gnupg apk-tools abuild || \ | ||
| sudo apt-get install -y dpkg-dev apt-utils createrepo-c gnupg | ||
|
|
||
| # Import GPG signing key (deb + rpm metadata). | ||
| printf '%s' "$DEB_KEY_PRIVATE" | gpg --batch --import | ||
| KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5; exit}') | ||
|
|
||
| # publish_repo <fmt> <indexer-fn> <public-key-file> <public-key-content> | ||
| # Common pull-existing → add-new → index → publish flow; the per-format index | ||
| # command is the only thing that differs (passed as a function name). | ||
| publish_repo() { | ||
| local fmt="$1" indexer="$2" pub_file="$3" pub_content="$4" | ||
| local dir="$WORK/$fmt" | ||
| mkdir -p "$dir" | ||
| aws s3 sync "s3://$BUCKET/$PREFIX/$fmt/" "$dir/" --exclude '*' --include "*.$fmt" || true | ||
| find . -path ./.git -prune -o -name "*.$fmt" -exec cp {} "$dir/" \; | ||
| ( cd "$dir" && "$indexer" ) | ||
| [ -n "$pub_content" ] && printf '%s' "$pub_content" > "$dir/$pub_file" | ||
| aws s3 sync "$dir/" "s3://$BUCKET/$PREFIX/$fmt/" | ||
| } | ||
|
|
||
| index_deb() { | ||
| dpkg-scanpackages . /dev/null > Packages && gzip -kf Packages | ||
| apt-ftparchive release . > Release | ||
| gpg --batch --yes --default-key "$KEYID" -abs -o Release.gpg Release | ||
| gpg --batch --yes --default-key "$KEYID" --clearsign -o InRelease Release | ||
| # Publish the DEARMORED (binary) keyring — apt's /etc/apt/trusted.gpg.d expects a | ||
| # binary keyring, not an ASCII-armored block, so `gpg --export` WITHOUT --armor. | ||
| gpg --export "$KEYID" > keboola.gpg | ||
| } | ||
| index_rpm() { createrepo_c .; } | ||
| index_apk() { | ||
| printf '%s' "$APK_KEY_PRIVATE" > "$WORK/apk_index.rsa" && chmod 600 "$WORK/apk_index.rsa" | ||
| apk index -o APKINDEX.tar.gz ./*.apk | ||
| abuild-sign -k "$WORK/apk_index.rsa" APKINDEX.tar.gz | ||
| } | ||
|
|
||
| # deb: index_deb writes its own (dearmored) keboola.gpg, so pass no pub-key content. | ||
| publish_repo deb index_deb "" "" | ||
| publish_repo rpm index_rpm keboola.gpg "${RPM_KEY_PUBLIC:-}" | ||
| if [ -z "${APK_KEY_PRIVATE:-}" ]; then | ||
| # No apk signing key configured — the apk index is genuinely opt-out, so skip it. | ||
| echo "::warning::APK_KEY_PRIVATE not set — skipping apk index (deb/rpm done)." | ||
| elif command -v abuild-sign >/dev/null 2>&1 && command -v apk >/dev/null 2>&1; then | ||
| publish_repo apk index_apk keboola.rsa.pub "${APK_KEY_PUBLIC:-}" | ||
| else | ||
| # Key IS set, so apk publishing is intended — but the tooling is missing (the | ||
| # `apk-tools abuild` apt install above fell back to the slimmer package set). | ||
| # publish-s3 only runs on real (non-pre-release) tags, so silently skipping here | ||
| # would ship a release with no apk index. Fail loudly — same policy as the | ||
| # DEB_KEY_PRIVATE guard at the top of this script. | ||
| echo "::error::APK_KEY_PRIVATE is set but abuild-sign/apk is unavailable — refusing to ship a real release without a signed apk index (check the 'apk-tools abuild' apt install above)." | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Repositories indexed and published under s3://$BUCKET/$PREFIX/{deb,rpm,apk}/" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/usr/bin/env bash | ||
| # Code-sign + notarize + staple a macOS binary. Required Apple secrets: | ||
| # APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 (Developer ID Application cert, base64 .p12) | ||
| # APPLE_DEVELOPER_CERTIFICATE_PASSWORD (.p12 password) | ||
| # APPLE_ACCOUNT_USERNAME (Apple ID email, e.g. apple@keboola.com) | ||
| # APPLE_ACCOUNT_PASSWORD (app-specific password) | ||
| # APPLE_TEAM_ID (e.g. 46P6KJ65M2) | ||
| # FAILS (exit 1) if the cert secret is absent — fail-closed so a real release never | ||
| # ships unsigned (pre-release tags mark this step continue-on-error). Usage: sign_notarize.sh <binary> | ||
| set -euo pipefail | ||
| BIN="$1" | ||
|
|
||
| for v in APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 APPLE_DEVELOPER_CERTIFICATE_PASSWORD \ | ||
| APPLE_ACCOUNT_USERNAME APPLE_ACCOUNT_PASSWORD APPLE_TEAM_ID; do | ||
| [ -n "${!v:-}" ] || { echo "::error::$v not set — refusing to ship an unsigned/un-notarized macOS binary."; exit 1; } | ||
| done | ||
|
|
||
| KEYCHAIN=build.keychain | ||
| security create-keychain -p actions "$KEYCHAIN" | ||
| security default-keychain -s "$KEYCHAIN" | ||
| security unlock-keychain -p actions "$KEYCHAIN" | ||
| printf '%s' "$APPLE_DEVELOPER_CERTIFICATE_P12_BASE64" | base64 -d > /tmp/cert.p12 | ||
| security import /tmp/cert.p12 -k "$KEYCHAIN" -P "${APPLE_DEVELOPER_CERTIFICATE_PASSWORD:-}" -T /usr/bin/codesign | ||
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k actions "$KEYCHAIN" >/dev/null | ||
|
|
||
| IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" | awk '/Developer ID Application/{print $2; exit}') | ||
| [ -n "$IDENTITY" ] || { echo "::error::no 'Developer ID Application' identity after import — wrong cert type/password or import failed"; exit 1; } | ||
| codesign --force --options runtime --timestamp --sign "$IDENTITY" "$BIN" | ||
|
|
||
| # Notarize with the Apple ID + app-specific password (notarytool supports this; no API key needed). | ||
| ZIP=/tmp/notarize.zip | ||
| ditto -c -k "$BIN" "$ZIP" | ||
| xcrun notarytool submit "$ZIP" \ | ||
| --apple-id "$APPLE_ACCOUNT_USERNAME" \ | ||
| --password "$APPLE_ACCOUNT_PASSWORD" \ | ||
| --team-id "$APPLE_TEAM_ID" \ | ||
| --wait | ||
| # Staple must succeed on a real release (an unstapled binary needs online | ||
| # notarization checks → worse offline install UX). Pre-release tags mark the | ||
| # whole signing step continue-on-error, so a hard failure here is safe there. | ||
| xcrun stapler staple "$BIN" | ||
| codesign --verify --verbose "$BIN" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # nfpm config — packages the frozen `kbagent` binary into deb / rpm / apk. | ||
| # | ||
| # nfpm (https://nfpm.goreleaser.com) is a standalone, language-agnostic packager. | ||
| # We do NOT use goreleaser (it builds Go); the binary is produced by PyInstaller in | ||
| # the release workflow's `freeze` matrix, and nfpm only wraps that prebuilt binary. | ||
| # | ||
| # The ${...} placeholders are NOT expanded by nfpm — build_packages.sh renders this | ||
| # file with `envsubst` first. Env vars: VERSION, PKG_ARCH (amd64|arm64), BIN_PATH. | ||
| name: keboola-cli2 | ||
| arch: ${PKG_ARCH} | ||
| platform: linux | ||
| version: ${VERSION} | ||
| section: utils | ||
| priority: optional | ||
| maintainer: "Keboola <dev@keboola.com>" | ||
| description: | | ||
| AI-friendly CLI for managing Keboola projects (kbagent). | ||
| Self-contained native binary; no Python runtime required. | ||
| vendor: "Keboola" | ||
| homepage: "https://github.com/keboola/cli" | ||
| license: "MIT" | ||
|
|
||
| contents: | ||
| - src: ${BIN_PATH} | ||
| dst: /usr/bin/kbagent | ||
| file_info: | ||
| mode: 0755 | ||
|
|
||
| # Signing keys are written by the workflow to /tmp/keys/* (org GPG keys, repo secrets). | ||
| deb: | ||
| signature: | ||
| key_file: /tmp/keys/deb.key | ||
| rpm: | ||
| signature: | ||
| key_file: /tmp/keys/rpm.key | ||
| apk: | ||
| signature: | ||
| key_file: /tmp/keys/apk.key |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/env bash | ||
| # Authenticode-sign a Windows .exe via Azure Key Vault + jsign (no PKCS#12 stored in | ||
| # GitHub). Required service-principal secrets: | ||
| # WINDOWS_SIGNING_TENANT_ID, WINDOWS_SIGNING_CLIENT_ID, WINDOWS_SIGNING_CLIENT_SECRET | ||
| # Key Vault keystore + cert alias default to the existing ones; override via env. | ||
| # FAILS (exit 1) if signing secrets are missing — the workflow marks this step | ||
| # continue-on-error on pre-releases, so dev builds stay non-blocking while a real | ||
| # release tag refuses to ship unsigned. Usage: sign.sh <exe-path> | ||
| set -euo pipefail | ||
| EXE="$1" | ||
| KEYVAULT="${AZURE_KEYVAULT_NAME:-kbc-cli-code-signing}" | ||
| ALIAS="${AZURE_CERT_ALIAS:-codesigning}" | ||
|
|
||
| for v in WINDOWS_SIGNING_TENANT_ID WINDOWS_SIGNING_CLIENT_ID WINDOWS_SIGNING_CLIENT_SECRET; do | ||
| [ -n "${!v:-}" ] || { echo "::error::$v not set — refusing to ship an unsigned Windows exe."; exit 1; } | ||
| done | ||
|
|
||
| # Service-principal token for the Key Vault data plane. | ||
| TOKEN=$(curl -sf -X POST "https://login.microsoftonline.com/${WINDOWS_SIGNING_TENANT_ID}/oauth2/v2.0/token" \ | ||
| --data-urlencode "grant_type=client_credentials" \ | ||
| --data-urlencode "client_id=${WINDOWS_SIGNING_CLIENT_ID}" \ | ||
| --data-urlencode "client_secret=${WINDOWS_SIGNING_CLIENT_SECRET}" \ | ||
| --data-urlencode "scope=https://vault.azure.net/.default" \ | ||
| | jq -er .access_token) | ||
| [ -n "$TOKEN" ] || { echo "::error::failed to obtain Azure access token"; exit 1; } | ||
|
Matovidlo marked this conversation as resolved.
|
||
|
|
||
| curl -fsSL -o /tmp/jsign.jar https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar | ||
| echo "05ca18d4ab7b8c2183289b5378d32860f0ea0f3bdab1f1b8cae5894fb225fa8a /tmp/jsign.jar" | sha256sum -c - | ||
| java -jar /tmp/jsign.jar \ | ||
|
Matovidlo marked this conversation as resolved.
|
||
| --storetype AZUREKEYVAULT \ | ||
| --keystore "$KEYVAULT" \ | ||
| --alias "$ALIAS" \ | ||
| --storepass "$TOKEN" \ | ||
| --tsaurl https://timestamp.digicert.com \ | ||
| --replace \ | ||
| "$EXE" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.