From b2370fbb84037fef0b078ec96d4f23c304ff2d21 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:08:51 +0200 Subject: [PATCH 01/31] chore: test chart-release.yml --- .github/workflows/chart-release.yml | 81 +++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 60a4a6a0..963a755e 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -6,6 +6,7 @@ on: jobs: helm-release: runs-on: ubuntu-latest + steps: - name: Checkout uses: actions/checkout@v4 @@ -18,7 +19,81 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" helm repo add bitnami https://charts.bitnami.com/bitnami - - name: Run chart-releaser - uses: exivity/chart-releaser-action@v1.1.0 + - name: Import GPG private key and setup keyring + run: | + echo "$HELM_GPG_PRIVATE_KEY" | base64 -d > private.key.gpg + gpg --batch --import private.key.gpg + + # Export secret keys to old format that Helm expects + gpg --export-secret-keys > ~/.gnupg/secring.gpg + + # List keys to verify import + gpg --list-secret-keys --keyid-format LONG + env: + HELM_GPG_PRIVATE_KEY: ${{ secrets.HELM_GPG_PRIVATE_KEY }} + + - name: Create GPG passphrase file + run: echo "$HELM_GPG_PASSPHRASE" > gpg-passphrase.txt + env: + HELM_GPG_PASSPHRASE: ${{ secrets.HELM_GPG_PASSPHRASE }} + + - name: Package and sign charts using Helm directly + run: | + # Get the GPG key name/email for signing + GPG_KEY_NAME=$(gpg --list-secret-keys --keyid-format LONG | grep uid | sed 's/.*] //') + echo "Using GPG key: $GPG_KEY_NAME" + + # Find all charts to package + for chart_dir in charts/*/; do + if [ -f "$chart_dir/Chart.yaml" ]; then + echo "Packaging and signing chart: $chart_dir" + # Package with signing using the KodeKloud method + helm package --sign "$chart_dir" \ + --key "$GPG_KEY_NAME" \ + --keyring ~/.gnupg/secring.gpg \ + --passphrase-file gpg-passphrase.txt + fi + done + + # List generated files + echo "Generated files:" + ls -la *.tgz *.prov 2>/dev/null || echo "No chart files found" + + - name: Create GitHub Release with signed charts + run: | + # Get chart version + CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') + RELEASE_TAG="exivity-$CHART_VERSION" + + echo "Creating release: $RELEASE_TAG" + + # Create release using GitHub CLI + gh release create "$RELEASE_TAG" \ + --title "Exivity Helm Chart $CHART_VERSION" \ + --notes "Signed Helm chart release for Exivity $CHART_VERSION" \ + *.tgz *.prov env: - CR_TOKEN: "${{ secrets.GH_BOT_TOKEN }}" + GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} + + - name: Export and upload public key + run: | + # Export public key using KodeKloud method + GPG_KEY_NAME=$(gpg --list-secret-keys --keyid-format LONG | grep uid | sed 's/.*] //') + echo "Exporting public key for: $GPG_KEY_NAME" + + # Export public key + gpg --export --armor "$GPG_KEY_NAME" > exivity-charts-signing-key.asc + + # Add to the same release + CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') + RELEASE_TAG="exivity-$CHART_VERSION" + + gh release upload "$RELEASE_TAG" exivity-charts-signing-key.asc + env: + GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} + + - name: Clean up sensitive files + if: always() + run: | + rm -f private.key.gpg gpg-passphrase.txt + rm -f ~/.gnupg/secring.gpg From 6abea7bc76f25a254365d4eb78ea8600c307556f Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:13:02 +0200 Subject: [PATCH 02/31] chore: trigger the chart-release CI --- .github/workflows/chart-release.yml | 81 ++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 963a755e..fefb5e1b 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -2,6 +2,10 @@ name: Release Charts on: workflow_dispatch: + pull_request: + paths: + - 'charts/**' + - '.github/workflows/chart-release.yml' jobs: helm-release: @@ -21,13 +25,63 @@ jobs: - name: Import GPG private key and setup keyring run: | - echo "$HELM_GPG_PRIVATE_KEY" | base64 -d > private.key.gpg - gpg --batch --import private.key.gpg + # Debug: Check if the secret exists and its format + echo "Checking GPG private key secret..." + if [ -z "$HELM_GPG_PRIVATE_KEY" ]; then + echo "❌ HELM_GPG_PRIVATE_KEY secret is empty" + exit 1 + fi + + echo "Secret length: ${#HELM_GPG_PRIVATE_KEY}" + echo "First 50 characters: ${HELM_GPG_PRIVATE_KEY:0:50}..." + + # Try to decode base64 with error handling + echo "Attempting to decode base64..." + # Remove any potential whitespace/newlines and decode + if echo "$HELM_GPG_PRIVATE_KEY" | tr -d '\n\r\t ' | base64 -d > private.key.gpg 2>/dev/null; then + echo "✅ Base64 decode successful (after cleaning whitespace)" + elif echo "$HELM_GPG_PRIVATE_KEY" | base64 -d > private.key.gpg 2>/dev/null; then + echo "✅ Base64 decode successful (direct)" + else + echo "❌ Base64 decode failed, trying alternative methods..." + + # Maybe it's not base64 encoded - try direct write + echo "$HELM_GPG_PRIVATE_KEY" > private.key.gpg + + # Check if it looks like a GPG key + if head -1 private.key.gpg | grep -q "BEGIN PGP"; then + echo "✅ Looks like a direct GPG key (not base64 encoded)" + else + echo "❌ Neither base64 nor direct GPG key format detected" + echo "Key starts with: $(head -c 100 private.key.gpg)" + exit 1 + fi + fi + + # Verify the decoded file looks like a GPG key + echo "Verifying GPG key format..." + if head -1 private.key.gpg | grep -q "BEGIN PGP"; then + echo "✅ GPG key format verified" + else + echo "❌ Decoded file doesn't look like a GPG key" + echo "File starts with: $(head -c 100 private.key.gpg)" + exit 1 + fi + + # Import the GPG key + echo "Importing GPG key..." + if gpg --batch --import private.key.gpg; then + echo "✅ GPG key imported successfully" + else + echo "❌ GPG key import failed" + exit 1 + fi # Export secret keys to old format that Helm expects gpg --export-secret-keys > ~/.gnupg/secring.gpg # List keys to verify import + echo "Imported GPG keys:" gpg --list-secret-keys --keyid-format LONG env: HELM_GPG_PRIVATE_KEY: ${{ secrets.HELM_GPG_PRIVATE_KEY }} @@ -59,7 +113,29 @@ jobs: echo "Generated files:" ls -la *.tgz *.prov 2>/dev/null || echo "No chart files found" + - name: Validate signed charts (PR only) + if: github.event_name == 'pull_request' + run: | + echo "🔍 Validating signed charts for PR..." + + # Check that both .tgz and .prov files exist + TGZ_COUNT=$(ls *.tgz 2>/dev/null | wc -l) + PROV_COUNT=$(ls *.prov 2>/dev/null | wc -l) + + echo "Found $TGZ_COUNT chart packages and $PROV_COUNT signature files" + + if [ "$TGZ_COUNT" -eq "$PROV_COUNT" ] && [ "$TGZ_COUNT" -gt 0 ]; then + echo "✅ Chart signing validation successful!" + echo "📦 Chart packages: $(ls *.tgz)" + echo "🔐 Signature files: $(ls *.prov)" + else + echo "❌ Chart signing validation failed!" + echo "Expected equal number of .tgz and .prov files" + exit 1 + fi + - name: Create GitHub Release with signed charts + if: github.event_name == 'workflow_dispatch' run: | # Get chart version CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') @@ -76,6 +152,7 @@ jobs: GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} - name: Export and upload public key + if: github.event_name == 'workflow_dispatch' run: | # Export public key using KodeKloud method GPG_KEY_NAME=$(gpg --list-secret-keys --keyid-format LONG | grep uid | sed 's/.*] //') From e53942c9d04f02e66f978e3b17dfc3899c78cdbc Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:23:39 +0200 Subject: [PATCH 03/31] chore: trigger ci --- .github/workflows/chart-release.yml | 78 +++++++---------------------- 1 file changed, 17 insertions(+), 61 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index fefb5e1b..5bbd9e65 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -25,77 +25,30 @@ jobs: - name: Import GPG private key and setup keyring run: | - # Debug: Check if the secret exists and its format - echo "Checking GPG private key secret..." - if [ -z "$HELM_GPG_PRIVATE_KEY" ]; then - echo "❌ HELM_GPG_PRIVATE_KEY secret is empty" - exit 1 - fi - - echo "Secret length: ${#HELM_GPG_PRIVATE_KEY}" - echo "First 50 characters: ${HELM_GPG_PRIVATE_KEY:0:50}..." - - # Try to decode base64 with error handling - echo "Attempting to decode base64..." - # Remove any potential whitespace/newlines and decode - if echo "$HELM_GPG_PRIVATE_KEY" | tr -d '\n\r\t ' | base64 -d > private.key.gpg 2>/dev/null; then - echo "✅ Base64 decode successful (after cleaning whitespace)" - elif echo "$HELM_GPG_PRIVATE_KEY" | base64 -d > private.key.gpg 2>/dev/null; then - echo "✅ Base64 decode successful (direct)" - else - echo "❌ Base64 decode failed, trying alternative methods..." - - # Maybe it's not base64 encoded - try direct write - echo "$HELM_GPG_PRIVATE_KEY" > private.key.gpg - - # Check if it looks like a GPG key - if head -1 private.key.gpg | grep -q "BEGIN PGP"; then - echo "✅ Looks like a direct GPG key (not base64 encoded)" - else - echo "❌ Neither base64 nor direct GPG key format detected" - echo "Key starts with: $(head -c 100 private.key.gpg)" - exit 1 - fi - fi - - # Verify the decoded file looks like a GPG key - echo "Verifying GPG key format..." - if head -1 private.key.gpg | grep -q "BEGIN PGP"; then - echo "✅ GPG key format verified" - else - echo "❌ Decoded file doesn't look like a GPG key" - echo "File starts with: $(head -c 100 private.key.gpg)" - exit 1 - fi + # Import GPG key directly from secret (no intermediate files) + echo "Importing GPG key directly from secret..." - # Import the GPG key - echo "Importing GPG key..." - if gpg --batch --import private.key.gpg; then - echo "✅ GPG key imported successfully" - else - echo "❌ GPG key import failed" - exit 1 - fi + # Decode and import in one step + echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import - # Export secret keys to old format that Helm expects + # Export to format Helm expects gpg --export-secret-keys > ~/.gnupg/secring.gpg # List keys to verify import echo "Imported GPG keys:" gpg --list-secret-keys --keyid-format LONG - env: - HELM_GPG_PRIVATE_KEY: ${{ secrets.HELM_GPG_PRIVATE_KEY }} - name: Create GPG passphrase file - run: echo "$HELM_GPG_PASSPHRASE" > gpg-passphrase.txt - env: - HELM_GPG_PASSPHRASE: ${{ secrets.HELM_GPG_PASSPHRASE }} + run: | + # Create passphrase file directly from secret + echo "${{ secrets.HELM_GPG_PASSPHRASE }}" > gpg-passphrase.txt + chmod 600 gpg-passphrase.txt - name: Package and sign charts using Helm directly run: | - # Get the GPG key name/email for signing - GPG_KEY_NAME=$(gpg --list-secret-keys --keyid-format LONG | grep uid | sed 's/.*] //') - echo "Using GPG key: $GPG_KEY_NAME" + # Get the GPG key ID directly from secret for signing + GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" + echo "Using GPG key ID: $GPG_KEY_ID" # Find all charts to package for chart_dir in charts/*/; do @@ -103,7 +56,7 @@ jobs: echo "Packaging and signing chart: $chart_dir" # Package with signing using the KodeKloud method helm package --sign "$chart_dir" \ - --key "$GPG_KEY_NAME" \ + --key "$GPG_KEY_ID" \ --keyring ~/.gnupg/secring.gpg \ --passphrase-file gpg-passphrase.txt fi @@ -172,5 +125,8 @@ jobs: - name: Clean up sensitive files if: always() run: | - rm -f private.key.gpg gpg-passphrase.txt + rm -f gpg-passphrase.txt rm -f ~/.gnupg/secring.gpg + # Clear GPG keyring + gpg --batch --yes --delete-secret-keys "${{ secrets.HELM_GPG_KEY_ID }}" 2>/dev/null || true + gpg --batch --yes --delete-keys "${{ secrets.HELM_GPG_KEY_ID }}" 2>/dev/null || true From 1365a24fa0209f653f2b10c1808d73a8ab23e01f Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:28:55 +0200 Subject: [PATCH 04/31] chore: trigger ci --- .github/workflows/chart-release.yml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 5bbd9e65..80274a03 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -28,11 +28,21 @@ jobs: # Import GPG key directly from secret (no intermediate files) echo "Importing GPG key directly from secret..." - # Decode and import in one step - echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + # Setup GPG environment for non-interactive use + export GPG_TTY=$(tty) + mkdir -p ~/.gnupg + echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + + # Decode and import in one step (suppress base64 warnings) + echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d 2>/dev/null | gpg --batch --import + + # Trust the imported key + GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" + echo "$GPG_KEY_ID:6:" | gpg --batch --import-ownertrust # Export to format Helm expects - gpg --export-secret-keys > ~/.gnupg/secring.gpg + gpg --batch --export-secret-keys > ~/.gnupg/secring.gpg # List keys to verify import echo "Imported GPG keys:" @@ -107,12 +117,12 @@ jobs: - name: Export and upload public key if: github.event_name == 'workflow_dispatch' run: | - # Export public key using KodeKloud method - GPG_KEY_NAME=$(gpg --list-secret-keys --keyid-format LONG | grep uid | sed 's/.*] //') - echo "Exporting public key for: $GPG_KEY_NAME" + # Export public key using the key ID directly + GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" + echo "Exporting public key for key ID: $GPG_KEY_ID" # Export public key - gpg --export --armor "$GPG_KEY_NAME" > exivity-charts-signing-key.asc + gpg --batch --export --armor "$GPG_KEY_ID" > exivity-charts-signing-key.asc # Add to the same release CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') From 45568a700b08317563b6409ed7117b9b59142350 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:30:21 +0200 Subject: [PATCH 05/31] chore: trigger ci --- .github/workflows/chart-release.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 80274a03..5780d9af 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -31,15 +31,19 @@ jobs: # Setup GPG environment for non-interactive use export GPG_TTY=$(tty) mkdir -p ~/.gnupg + chmod 700 ~/.gnupg echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + chmod 600 ~/.gnupg/gpg-agent.conf ~/.gnupg/gpg.conf # Decode and import in one step (suppress base64 warnings) echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d 2>/dev/null | gpg --batch --import - # Trust the imported key + # Trust the imported key using the full fingerprint GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" - echo "$GPG_KEY_ID:6:" | gpg --batch --import-ownertrust + FULL_FINGERPRINT=$(gpg --list-secret-keys --keyid-format LONG --with-colons | grep fpr | head -1 | cut -d: -f10) + echo "Full fingerprint: $FULL_FINGERPRINT" + echo "$FULL_FINGERPRINT:6:" | gpg --batch --import-ownertrust # Export to format Helm expects gpg --batch --export-secret-keys > ~/.gnupg/secring.gpg From 00f18638fd1c54921864f10919586e0aa66ef3b6 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 15:39:02 +0200 Subject: [PATCH 06/31] chore: trigger ci --- .github/workflows/chart-release.yml | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 5780d9af..0e30a097 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -32,25 +32,31 @@ jobs: export GPG_TTY=$(tty) mkdir -p ~/.gnupg chmod 700 ~/.gnupg - echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf - echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + + # Configure GPG for CI/batch mode + echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf + echo "trust-model always" >> ~/.gnupg/gpg.conf + echo "batch" >> ~/.gnupg/gpg.conf + echo "no-tty" >> ~/.gnupg/gpg.conf + + echo "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf chmod 600 ~/.gnupg/gpg-agent.conf ~/.gnupg/gpg.conf # Decode and import in one step (suppress base64 warnings) echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d 2>/dev/null | gpg --batch --import - # Trust the imported key using the full fingerprint - GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" - FULL_FINGERPRINT=$(gpg --list-secret-keys --keyid-format LONG --with-colons | grep fpr | head -1 | cut -d: -f10) - echo "Full fingerprint: $FULL_FINGERPRINT" - echo "$FULL_FINGERPRINT:6:" | gpg --batch --import-ownertrust - - # Export to format Helm expects + # Create legacy format keyrings that Helm expects + gpg --batch --export > ~/.gnupg/pubring.gpg gpg --batch --export-secret-keys > ~/.gnupg/secring.gpg - # List keys to verify import + # Verify key import (trust-model always is set in gpg.conf, so no ownertrust needed) echo "Imported GPG keys:" gpg --list-secret-keys --keyid-format LONG + + # Verify we can use the key for signing + GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" + echo "${{ secrets.HELM_GPG_KEY_ID }}" + echo "Key ID to use for signing: $GPG_KEY_ID" - name: Create GPG passphrase file run: | @@ -68,7 +74,7 @@ jobs: for chart_dir in charts/*/; do if [ -f "$chart_dir/Chart.yaml" ]; then echo "Packaging and signing chart: $chart_dir" - # Package with signing using the KodeKloud method + # Package with signing using legacy keyring format helm package --sign "$chart_dir" \ --key "$GPG_KEY_ID" \ --keyring ~/.gnupg/secring.gpg \ From afeacac2137c349783adb743c0cc1dd8f5bf8c3d Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 16:14:27 +0200 Subject: [PATCH 07/31] chore: trigger ci --- .github/workflows/chart-release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 0e30a097..11d2ebd7 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -47,7 +47,9 @@ jobs: # Create legacy format keyrings that Helm expects gpg --batch --export > ~/.gnupg/pubring.gpg - gpg --batch --export-secret-keys > ~/.gnupg/secring.gpg + + # Export secret keys with passphrase (using gpg-preset-passphrase or temp file) + echo "${{ secrets.HELM_GPG_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg # Verify key import (trust-model always is set in gpg.conf, so no ownertrust needed) echo "Imported GPG keys:" From fbd9731b2347d04e9450eaf5d065fb97d27f3bbf Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 16:41:48 +0200 Subject: [PATCH 08/31] chore: apply signs manually for supports Ed25519 --- .github/workflows/chart-release.yml | 33 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 11d2ebd7..bcb24916 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -55,6 +55,10 @@ jobs: echo "Imported GPG keys:" gpg --list-secret-keys --keyid-format LONG + # Check key algorithm type for Helm compatibility + echo "Key algorithm details:" + gpg --list-secret-keys --with-subkey-fingerprint --keyid-format LONG + # Verify we can use the key for signing GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" echo "${{ secrets.HELM_GPG_KEY_ID }}" @@ -72,15 +76,30 @@ jobs: GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" echo "Using GPG key ID: $GPG_KEY_ID" - # Find all charts to package + # Find all charts to package and sign for chart_dir in charts/*/; do if [ -f "$chart_dir/Chart.yaml" ]; then - echo "Packaging and signing chart: $chart_dir" - # Package with signing using legacy keyring format - helm package --sign "$chart_dir" \ - --key "$GPG_KEY_ID" \ - --keyring ~/.gnupg/secring.gpg \ - --passphrase-file gpg-passphrase.txt + echo "Packaging chart: $chart_dir" + + # Package chart without signing first (since Ed25519 not supported by helm) + helm package "$chart_dir" + + # Get the generated chart file name + CHART_NAME=$(basename "$chart_dir") + CHART_VERSION=$(helm show chart "$chart_dir" | grep '^version:' | awk '{print $2}') + CHART_FILE="${CHART_NAME}-${CHART_VERSION}.tgz" + + echo "Signing chart package: $CHART_FILE" + + # Sign the chart package manually with GPG (supports Ed25519) + echo "${{ secrets.HELM_GPG_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback \ + --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ + --detach-sign --armor "$CHART_FILE" + + # Create .prov file (Helm provenance format) + mv "${CHART_FILE}.asc" "${CHART_FILE}.prov" + + echo "✅ Successfully signed: $CHART_FILE -> ${CHART_FILE}.prov" fi done From e9406eff413c47f8e8747a1d449638320fed679d Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Fri, 20 Jun 2025 16:54:06 +0200 Subject: [PATCH 09/31] chore: refactor --- .github/workflows/chart-release.yml | 147 +++++----------------------- 1 file changed, 25 insertions(+), 122 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index bcb24916..7ac13b2e 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -10,6 +10,9 @@ on: jobs: helm-release: runs-on: ubuntu-latest + env: + GPG_KEY_ID: ${{ secrets.HELM_GPG_KEY_ID }} + GPG_PASSPHRASE: ${{ secrets.HELM_GPG_PASSPHRASE }} steps: - name: Checkout @@ -21,153 +24,53 @@ jobs: run: | git config user.name "$GITHUB_ACTOR" git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - helm repo add bitnami https://charts.bitnami.com/bitnami - - name: Import GPG private key and setup keyring + - name: Configure GPG run: | - # Import GPG key directly from secret (no intermediate files) - echo "Importing GPG key directly from secret..." - - # Setup GPG environment for non-interactive use - export GPG_TTY=$(tty) mkdir -p ~/.gnupg chmod 700 ~/.gnupg - - # Configure GPG for CI/batch mode echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - echo "trust-model always" >> ~/.gnupg/gpg.conf - echo "batch" >> ~/.gnupg/gpg.conf - echo "no-tty" >> ~/.gnupg/gpg.conf - - echo "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf - chmod 600 ~/.gnupg/gpg-agent.conf ~/.gnupg/gpg.conf - - # Decode and import in one step (suppress base64 warnings) - echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d 2>/dev/null | gpg --batch --import - - # Create legacy format keyrings that Helm expects - gpg --batch --export > ~/.gnupg/pubring.gpg - - # Export secret keys with passphrase (using gpg-preset-passphrase or temp file) - echo "${{ secrets.HELM_GPG_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - - # Verify key import (trust-model always is set in gpg.conf, so no ownertrust needed) - echo "Imported GPG keys:" - gpg --list-secret-keys --keyid-format LONG - - # Check key algorithm type for Helm compatibility - echo "Key algorithm details:" - gpg --list-secret-keys --with-subkey-fingerprint --keyid-format LONG - - # Verify we can use the key for signing - GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" - echo "${{ secrets.HELM_GPG_KEY_ID }}" - echo "Key ID to use for signing: $GPG_KEY_ID" - - - name: Create GPG passphrase file - run: | - # Create passphrase file directly from secret - echo "${{ secrets.HELM_GPG_PASSPHRASE }}" > gpg-passphrase.txt - chmod 600 gpg-passphrase.txt + echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - - name: Package and sign charts using Helm directly + - name: Package and Sign Charts run: | - # Get the GPG key ID directly from secret for signing - GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" - echo "Using GPG key ID: $GPG_KEY_ID" - - # Find all charts to package and sign for chart_dir in charts/*/; do - if [ -f "$chart_dir/Chart.yaml" ]; then - echo "Packaging chart: $chart_dir" - - # Package chart without signing first (since Ed25519 not supported by helm) - helm package "$chart_dir" - - # Get the generated chart file name - CHART_NAME=$(basename "$chart_dir") - CHART_VERSION=$(helm show chart "$chart_dir" | grep '^version:' | awk '{print $2}') - CHART_FILE="${CHART_NAME}-${CHART_VERSION}.tgz" - - echo "Signing chart package: $CHART_FILE" - - # Sign the chart package manually with GPG (supports Ed25519) - echo "${{ secrets.HELM_GPG_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback \ - --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ - --detach-sign --armor "$CHART_FILE" - - # Create .prov file (Helm provenance format) - mv "${CHART_FILE}.asc" "${CHART_FILE}.prov" - - echo "✅ Successfully signed: $CHART_FILE -> ${CHART_FILE}.prov" - fi + [ -f "$chart_dir/Chart.yaml" ] || continue + helm package "$chart_dir" + CHART_FILE=$(ls -t *.tgz | head -n 1) + echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ + --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ + --detach-sign --armor "$CHART_FILE" + mv "${CHART_FILE}.asc" "${CHART_FILE}.prov" done - - # List generated files - echo "Generated files:" - ls -la *.tgz *.prov 2>/dev/null || echo "No chart files found" - - name: Validate signed charts (PR only) + - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' run: | - echo "🔍 Validating signed charts for PR..." - - # Check that both .tgz and .prov files exist - TGZ_COUNT=$(ls *.tgz 2>/dev/null | wc -l) - PROV_COUNT=$(ls *.prov 2>/dev/null | wc -l) - - echo "Found $TGZ_COUNT chart packages and $PROV_COUNT signature files" - - if [ "$TGZ_COUNT" -eq "$PROV_COUNT" ] && [ "$TGZ_COUNT" -gt 0 ]; then - echo "✅ Chart signing validation successful!" - echo "📦 Chart packages: $(ls *.tgz)" - echo "🔐 Signature files: $(ls *.prov)" - else + [ $(ls *.tgz 2>/dev/null | wc -l) -eq $(ls *.prov 2>/dev/null | wc -l) ] || { echo "❌ Chart signing validation failed!" - echo "Expected equal number of .tgz and .prov files" exit 1 - fi + } + echo "✅ All charts signed correctly" - - name: Create GitHub Release with signed charts + - name: Create Release (Manual trigger only) if: github.event_name == 'workflow_dispatch' run: | - # Get chart version CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') RELEASE_TAG="exivity-$CHART_VERSION" - echo "Creating release: $RELEASE_TAG" + gpg --export --armor "$GPG_KEY_ID" > signing-key.asc - # Create release using GitHub CLI gh release create "$RELEASE_TAG" \ --title "Exivity Helm Chart $CHART_VERSION" \ - --notes "Signed Helm chart release for Exivity $CHART_VERSION" \ - *.tgz *.prov - env: - GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} - - - name: Export and upload public key - if: github.event_name == 'workflow_dispatch' - run: | - # Export public key using the key ID directly - GPG_KEY_ID="${{ secrets.HELM_GPG_KEY_ID }}" - echo "Exporting public key for key ID: $GPG_KEY_ID" - - # Export public key - gpg --batch --export --armor "$GPG_KEY_ID" > exivity-charts-signing-key.asc - - # Add to the same release - CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') - RELEASE_TAG="exivity-$CHART_VERSION" - - gh release upload "$RELEASE_TAG" exivity-charts-signing-key.asc + --notes "Signed Helm chart release" \ + *.tgz *.prov signing-key.asc env: GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} - - name: Clean up sensitive files + - name: Cleanup if: always() run: | - rm -f gpg-passphrase.txt - rm -f ~/.gnupg/secring.gpg - # Clear GPG keyring - gpg --batch --yes --delete-secret-keys "${{ secrets.HELM_GPG_KEY_ID }}" 2>/dev/null || true - gpg --batch --yes --delete-keys "${{ secrets.HELM_GPG_KEY_ID }}" 2>/dev/null || true + gpg --batch --yes --delete-secret-keys "$GPG_KEY_ID" 2>/dev/null || true + gpg --batch --yes --delete-keys "$GPG_KEY_ID" 2>/dev/null || true \ No newline at end of file From 1d2f0c572be0d5d2fc396d33bcbca71acd524b75 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Tue, 24 Jun 2025 11:14:08 +0200 Subject: [PATCH 10/31] chore: eliminate .asc format --- .github/workflows/chart-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 7ac13b2e..86768010 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -41,8 +41,7 @@ jobs: CHART_FILE=$(ls -t *.tgz | head -n 1) echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ - --detach-sign --armor "$CHART_FILE" - mv "${CHART_FILE}.asc" "${CHART_FILE}.prov" + --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" done - name: Validate Signed Charts (PR only) From f88005f5063d434700045da3326de85e06c32e5e Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Tue, 24 Jun 2025 11:24:38 +0200 Subject: [PATCH 11/31] chore: check output of packaged chart and .prov file --- .github/workflows/chart-release.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 86768010..6a0a57c8 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -44,6 +44,19 @@ jobs: --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" done + - name: Show packaged chart and .prov file content + run: | + for chart_file in *.tgz; do + prov_file="${chart_file}.prov" + echo "== 📦 Packaged Chart: $chart_file ==" + tar -tzf "$chart_file" + + echo "== 🔐 Signature File: $prov_file (base64 encoded) ==" + base64 "$prov_file" + + echo "" + done + - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' run: | From f3a68fdb85e57597d6597fca2d933db45dd04f2d Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Tue, 24 Jun 2025 11:29:10 +0200 Subject: [PATCH 12/31] chore: validate signed charts properly --- .github/workflows/chart-release.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 6a0a57c8..7990c0f3 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -60,11 +60,11 @@ jobs: - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' run: | - [ $(ls *.tgz 2>/dev/null | wc -l) -eq $(ls *.prov 2>/dev/null | wc -l) ] || { - echo "❌ Chart signing validation failed!" - exit 1 - } - echo "✅ All charts signed correctly" + for chart in *.tgz; do + echo "🔍 Verifying $chart..." + helm verify "$chart" + done + echo "✅ All charts are properly signed and verified" - name: Create Release (Manual trigger only) if: github.event_name == 'workflow_dispatch' From c888cc6bcf0975a629e2fba7cc93b6e51b924e80 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Tue, 24 Jun 2025 11:36:18 +0200 Subject: [PATCH 13/31] chore: update validate signed charts --- .github/workflows/chart-release.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 7990c0f3..ef4276a5 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -44,22 +44,21 @@ jobs: --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" done - - name: Show packaged chart and .prov file content - run: | - for chart_file in *.tgz; do - prov_file="${chart_file}.prov" - echo "== 📦 Packaged Chart: $chart_file ==" - tar -tzf "$chart_file" - - echo "== 🔐 Signature File: $prov_file (base64 encoded) ==" - base64 "$prov_file" - - echo "" - done - - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' run: | + # Setup GPG for verification (helm verify needs keyring) + mkdir -p ~/.gnupg + chmod 700 ~/.gnupg + echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf + + # Import the public key for verification + echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + + # Create the public keyring that helm verify expects + gpg --batch --export > ~/.gnupg/pubring.gpg + + # Verify each chart for chart in *.tgz; do echo "🔍 Verifying $chart..." helm verify "$chart" From 7f2de5e6deb3985b7da8751cd6b9aceeb57b89d9 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:04:56 +0200 Subject: [PATCH 14/31] chore: updated gpgkey with RSA type --- .github/workflows/chart-release.yml | 32 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index ef4276a5..dae48c19 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -11,8 +11,8 @@ jobs: helm-release: runs-on: ubuntu-latest env: - GPG_KEY_ID: ${{ secrets.HELM_GPG_KEY_ID }} - GPG_PASSPHRASE: ${{ secrets.HELM_GPG_PASSPHRASE }} + GPG_KEY_ID: ${{ secrets.HELM_RSA_KEY_ID }} + GPG_PASSPHRASE: ${{ secrets.HELM_RSA_PASSPHRASE }} steps: - name: Checkout @@ -30,8 +30,8 @@ jobs: mkdir -p ~/.gnupg chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import - echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + echo "${{ secrets.HELM_RSA_PASSPHRASE }}" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - name: Package and Sign Charts run: | @@ -39,7 +39,7 @@ jobs: [ -f "$chart_dir/Chart.yaml" ] || continue helm package "$chart_dir" CHART_FILE=$(ls -t *.tgz | head -n 1) - echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ + echo "${{ secrets.HELM_RSA_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback \ # Fixed: Use HELM_RSA_PASSPHRASE --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" done @@ -52,21 +52,33 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Import the public key for verification - echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + # Import the RSA public key for verification + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | base64 -d | gpg --batch --import # Create the public keyring that helm verify expects gpg --batch --export > ~/.gnupg/pubring.gpg - # Verify each chart + # Verify each chart (should now work with RSA key) for chart in *.tgz; do echo "🔍 Verifying $chart..." - helm verify "$chart" + helm verify "$chart" || { echo "❌ Verification failed"; exit 1; } done echo "✅ All charts are properly signed and verified" + - name: Show packaged chart and .prov file content + run: | + for chart_file in *.tgz; do + prov_file="${chart_file}.prov" + echo "== 📦 Packaged Chart: $chart_file ==" + tar -tzf "$chart_file" + + echo "== 🔐 Signature File: $prov_file (base64 encoded) ==" + base64 "$prov_file" + + echo "" + done + - name: Create Release (Manual trigger only) - if: github.event_name == 'workflow_dispatch' run: | CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') RELEASE_TAG="exivity-$CHART_VERSION" From 6b929f5bb29b44ba4d3ce50549d899182e5de776 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:11:43 +0200 Subject: [PATCH 15/31] chore: test --- .github/workflows/chart-release.yml | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index dae48c19..b43e9b58 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -11,7 +11,7 @@ jobs: helm-release: runs-on: ubuntu-latest env: - GPG_KEY_ID: ${{ secrets.HELM_RSA_KEY_ID }} + GPG_KEY_ID: ${{ secrets.HELM_RSA_KEY_ID }} GPG_PASSPHRASE: ${{ secrets.HELM_RSA_PASSPHRASE }} steps: @@ -31,7 +31,7 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | base64 -d | gpg --batch --import - echo "${{ secrets.HELM_RSA_PASSPHRASE }}" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg + echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - name: Package and Sign Charts run: | @@ -39,7 +39,7 @@ jobs: [ -f "$chart_dir/Chart.yaml" ] || continue helm package "$chart_dir" CHART_FILE=$(ls -t *.tgz | head -n 1) - echo "${{ secrets.HELM_RSA_PASSPHRASE }}" | gpg --batch --yes --pinentry-mode loopback \ # Fixed: Use HELM_RSA_PASSPHRASE + echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" done @@ -52,33 +52,21 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Import the RSA public key for verification - echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + # Import the public key for verification + echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import # Create the public keyring that helm verify expects gpg --batch --export > ~/.gnupg/pubring.gpg - # Verify each chart (should now work with RSA key) + # Verify each chart for chart in *.tgz; do echo "🔍 Verifying $chart..." - helm verify "$chart" || { echo "❌ Verification failed"; exit 1; } + helm verify "$chart" done echo "✅ All charts are properly signed and verified" - - name: Show packaged chart and .prov file content - run: | - for chart_file in *.tgz; do - prov_file="${chart_file}.prov" - echo "== 📦 Packaged Chart: $chart_file ==" - tar -tzf "$chart_file" - - echo "== 🔐 Signature File: $prov_file (base64 encoded) ==" - base64 "$prov_file" - - echo "" - done - - name: Create Release (Manual trigger only) + if: github.event_name == 'workflow_dispatch' run: | CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') RELEASE_TAG="exivity-$CHART_VERSION" From 8b096f962f8ab44e298a85fc5c6b011c44d0c73b Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:18:42 +0200 Subject: [PATCH 16/31] chore: test --- .github/workflows/chart-release.yml | 36 +++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index b43e9b58..1f490a56 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -30,7 +30,31 @@ jobs: mkdir -p ~/.gnupg chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + + # Write the base64 key to a file first + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" > private.key.b64 + + # Decode with error handling + if ! base64 -d private.key.b64 > private.key; then + echo "❌ Base64 decoding failed. Ensure your HELM_RSA_PRIVATE_KEY is properly base64 encoded." + echo "First few chars of secret: ${HELM_RSA_PRIVATE_KEY:0:20}..." + exit 1 + fi + + # Import with error handling + if ! gpg --batch --import private.key; then + echo "❌ GPG import failed. Verify the key format is correct." + echo "Key starts with: $(head -c 50 private.key)" + exit 1 + fi + + # Verify key exists + gpg --list-secret-keys --keyid-format LONG || { + echo "❌ No keys found after import" + exit 1 + } + + # Export to secring.gpg echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - name: Package and Sign Charts @@ -47,21 +71,19 @@ jobs: - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' run: | - # Setup GPG for verification (helm verify needs keyring) mkdir -p ~/.gnupg chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Import the public key for verification - echo "${{ secrets.HELM_GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import + # Use the same RSA key for verification + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" > verify.key.b64 + base64 -d verify.key.b64 | gpg --batch --import - # Create the public keyring that helm verify expects gpg --batch --export > ~/.gnupg/pubring.gpg - # Verify each chart for chart in *.tgz; do echo "🔍 Verifying $chart..." - helm verify "$chart" + helm verify "$chart" || { echo "❌ Verification failed for $chart"; exit 1; } done echo "✅ All charts are properly signed and verified" From 26aa6ad665d46e7138f0bdb90e974f0466b0be18 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:20:53 +0200 Subject: [PATCH 17/31] test --- .github/workflows/chart-release.yml | 46 ++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 1f490a56..d08f8b9e 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -31,14 +31,30 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Write the base64 key to a file first - echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" > private.key.b64 + # Check if the secret is already armored text or base64 encoded + SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" - # Decode with error handling - if ! base64 -d private.key.b64 > private.key; then - echo "❌ Base64 decoding failed. Ensure your HELM_RSA_PRIVATE_KEY is properly base64 encoded." - echo "First few chars of secret: ${HELM_RSA_PRIVATE_KEY:0:20}..." - exit 1 + if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then + echo "📝 Secret appears to be raw armored GPG key" + echo "$SECRET_CONTENT" > private.key + else + echo "📝 Secret appears to be base64 encoded, decoding..." + # Clean the base64 key (remove whitespace/newlines) and decode + echo "$SECRET_CONTENT" | tr -d ' \n\r\t' > private.key.b64 + + # Decode with error handling + if ! base64 -d private.key.b64 > private.key 2>/dev/null; then + echo "❌ Base64 decoding failed. Checking secret format..." + echo "Secret length: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | wc -c)" + echo "First 50 chars: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | head -c 50)..." + echo "Last 50 chars: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | tail -c 50)" + echo "" + echo "💡 Options to fix:" + echo "1. Use raw armored key: gpg --export-secret-keys --armor KEY_ID" + echo "2. Use base64 encoded: gpg --export-secret-keys --armor KEY_ID | base64 -w 0" + exit 1 + fi + rm -f private.key.b64 fi # Import with error handling @@ -56,6 +72,9 @@ jobs: # Export to secring.gpg echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg + + # Cleanup sensitive files + rm -f private.key - name: Package and Sign Charts run: | @@ -75,9 +94,16 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Use the same RSA key for verification - echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" > verify.key.b64 - base64 -d verify.key.b64 | gpg --batch --import + # Use the same RSA key for verification (handle both armored and base64) + SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" + + if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then + echo "$SECRET_CONTENT" | gpg --batch --import + else + echo "$SECRET_CONTENT" | tr -d ' \n\r\t' > verify.key.b64 + base64 -d verify.key.b64 2>/dev/null | gpg --batch --import + rm -f verify.key.b64 + fi gpg --batch --export > ~/.gnupg/pubring.gpg From 4fce19fadd960495352e24a92619ac0e73f2cbfd Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:25:28 +0200 Subject: [PATCH 18/31] chore: update Package and Sign Charts --- .github/workflows/chart-release.yml | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index d08f8b9e..297467f6 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -78,14 +78,27 @@ jobs: - name: Package and Sign Charts run: | + # Create passphrase file for Helm + echo "$GPG_PASSPHRASE" > /tmp/passphrase.txt + chmod 600 /tmp/passphrase.txt + for chart_dir in charts/*/; do [ -f "$chart_dir/Chart.yaml" ] || continue - helm package "$chart_dir" - CHART_FILE=$(ls -t *.tgz | head -n 1) - echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ - --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ - --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" + echo "📦 Packaging and signing chart: $chart_dir" + + # Use helm package --sign (should work with RSA keys) + helm package --sign "$chart_dir" \ + --key "$GPG_KEY_ID" \ + --keyring ~/.gnupg/secring.gpg \ + --passphrase-file /tmp/passphrase.txt done + + # Clean up passphrase file + rm -f /tmp/passphrase.txt + + # List generated files + echo "Generated files:" + ls -la *.tgz *.prov 2>/dev/null || echo "No chart files found" - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' From e5b6eb398527cbeac800af110ad9512021e8132a Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:28:59 +0200 Subject: [PATCH 19/31] chore: test --- .github/workflows/chart-release.yml | 63 ++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 297467f6..1bf91663 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -70,14 +70,55 @@ jobs: exit 1 } - # Export to secring.gpg - echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg + # Export to legacy GPG format that Helm expects (GPG v2 compatibility) + echo "Exporting keys to legacy GPG format for Helm compatibility..." + + # Export public keys to legacy format + if ! gpg --batch --export > ~/.gnupg/pubring.gpg; then + echo "❌ Failed to export public keys" + exit 1 + fi + + # Export secret keys to legacy format (with passphrase) + if ! echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg; then + echo "❌ Failed to export secret keys" + exit 1 + fi + + # Verify the keyring files were created and have content + if [ ! -s ~/.gnupg/secring.gpg ] || [ ! -s ~/.gnupg/pubring.gpg ]; then + echo "❌ Keyring files are empty or not created" + exit 1 + fi + + echo "✅ Legacy keyring files created successfully:" + echo " pubring.gpg: $(wc -c < ~/.gnupg/pubring.gpg) bytes" + echo " secring.gpg: $(wc -c < ~/.gnupg/secring.gpg) bytes" # Cleanup sensitive files rm -f private.key - name: Package and Sign Charts run: | + # Verify GPG setup before signing + echo "🔍 Verifying GPG setup for Helm..." + echo "Available secret keys:" + gpg --list-secret-keys --keyid-format LONG + + echo "Keyring files:" + ls -la ~/.gnupg/secring.gpg ~/.gnupg/pubring.gpg + + # Get the key name/email for Helm (not the key ID) + KEY_NAME=$(gpg --list-secret-keys --with-colons "$GPG_KEY_ID" | grep "^uid" | head -1 | cut -d: -f10) + if [ -z "$KEY_NAME" ]; then + echo "❌ Could not find key name for key ID: $GPG_KEY_ID" + exit 1 + fi + echo "Using key name for Helm: $KEY_NAME" + + echo "Testing GPG signing capability..." + echo "test" | echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 --local-user "$GPG_KEY_ID" --sign --armor + # Create passphrase file for Helm echo "$GPG_PASSPHRASE" > /tmp/passphrase.txt chmod 600 /tmp/passphrase.txt @@ -86,11 +127,21 @@ jobs: [ -f "$chart_dir/Chart.yaml" ] || continue echo "📦 Packaging and signing chart: $chart_dir" - # Use helm package --sign (should work with RSA keys) - helm package --sign "$chart_dir" \ - --key "$GPG_KEY_ID" \ + # Use helm package --sign with key name (not key ID) + if ! helm package --sign "$chart_dir" \ + --key "$KEY_NAME" \ --keyring ~/.gnupg/secring.gpg \ - --passphrase-file /tmp/passphrase.txt + --passphrase-file /tmp/passphrase.txt; then + echo "❌ Helm signing failed. Trying alternative approach..." + + # Fallback: package first, then sign manually + helm package "$chart_dir" + CHART_FILE=$(ls -t *.tgz | head -n 1) + echo "Signing $CHART_FILE manually..." + echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ + --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ + --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" + fi done # Clean up passphrase file From df06a3c43dc3d7b2a6381ed3af17798c51cdc8cb Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:34:29 +0200 Subject: [PATCH 20/31] chore: remove debugging code --- .github/workflows/chart-release.yml | 111 +++------------------------- 1 file changed, 12 insertions(+), 99 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 1bf91663..8659663c 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -31,93 +31,28 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Check if the secret is already armored text or base64 encoded + # Handle both raw armored keys and base64 encoded keys SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then - echo "📝 Secret appears to be raw armored GPG key" echo "$SECRET_CONTENT" > private.key else - echo "📝 Secret appears to be base64 encoded, decoding..." - # Clean the base64 key (remove whitespace/newlines) and decode echo "$SECRET_CONTENT" | tr -d ' \n\r\t' > private.key.b64 - - # Decode with error handling - if ! base64 -d private.key.b64 > private.key 2>/dev/null; then - echo "❌ Base64 decoding failed. Checking secret format..." - echo "Secret length: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | wc -c)" - echo "First 50 chars: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | head -c 50)..." - echo "Last 50 chars: $(echo '${{ secrets.HELM_RSA_PRIVATE_KEY }}' | tail -c 50)" - echo "" - echo "💡 Options to fix:" - echo "1. Use raw armored key: gpg --export-secret-keys --armor KEY_ID" - echo "2. Use base64 encoded: gpg --export-secret-keys --armor KEY_ID | base64 -w 0" - exit 1 - fi + base64 -d private.key.b64 > private.key 2>/dev/null rm -f private.key.b64 fi - # Import with error handling - if ! gpg --batch --import private.key; then - echo "❌ GPG import failed. Verify the key format is correct." - echo "Key starts with: $(head -c 50 private.key)" - exit 1 - fi - - # Verify key exists - gpg --list-secret-keys --keyid-format LONG || { - echo "❌ No keys found after import" - exit 1 - } - - # Export to legacy GPG format that Helm expects (GPG v2 compatibility) - echo "Exporting keys to legacy GPG format for Helm compatibility..." - - # Export public keys to legacy format - if ! gpg --batch --export > ~/.gnupg/pubring.gpg; then - echo "❌ Failed to export public keys" - exit 1 - fi - - # Export secret keys to legacy format (with passphrase) - if ! echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg; then - echo "❌ Failed to export secret keys" - exit 1 - fi - - # Verify the keyring files were created and have content - if [ ! -s ~/.gnupg/secring.gpg ] || [ ! -s ~/.gnupg/pubring.gpg ]; then - echo "❌ Keyring files are empty or not created" - exit 1 - fi - - echo "✅ Legacy keyring files created successfully:" - echo " pubring.gpg: $(wc -c < ~/.gnupg/pubring.gpg) bytes" - echo " secring.gpg: $(wc -c < ~/.gnupg/secring.gpg) bytes" + # Import and export to legacy GPG format for Helm compatibility + gpg --batch --import private.key + gpg --batch --export > ~/.gnupg/pubring.gpg + echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - # Cleanup sensitive files rm -f private.key - name: Package and Sign Charts run: | - # Verify GPG setup before signing - echo "🔍 Verifying GPG setup for Helm..." - echo "Available secret keys:" - gpg --list-secret-keys --keyid-format LONG - - echo "Keyring files:" - ls -la ~/.gnupg/secring.gpg ~/.gnupg/pubring.gpg - - # Get the key name/email for Helm (not the key ID) + # Get the key name for Helm KEY_NAME=$(gpg --list-secret-keys --with-colons "$GPG_KEY_ID" | grep "^uid" | head -1 | cut -d: -f10) - if [ -z "$KEY_NAME" ]; then - echo "❌ Could not find key name for key ID: $GPG_KEY_ID" - exit 1 - fi - echo "Using key name for Helm: $KEY_NAME" - - echo "Testing GPG signing capability..." - echo "test" | echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 --local-user "$GPG_KEY_ID" --sign --armor # Create passphrase file for Helm echo "$GPG_PASSPHRASE" > /tmp/passphrase.txt @@ -125,31 +60,13 @@ jobs: for chart_dir in charts/*/; do [ -f "$chart_dir/Chart.yaml" ] || continue - echo "📦 Packaging and signing chart: $chart_dir" - - # Use helm package --sign with key name (not key ID) - if ! helm package --sign "$chart_dir" \ + helm package --sign "$chart_dir" \ --key "$KEY_NAME" \ --keyring ~/.gnupg/secring.gpg \ - --passphrase-file /tmp/passphrase.txt; then - echo "❌ Helm signing failed. Trying alternative approach..." - - # Fallback: package first, then sign manually - helm package "$chart_dir" - CHART_FILE=$(ls -t *.tgz | head -n 1) - echo "Signing $CHART_FILE manually..." - echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback \ - --passphrase-fd 0 --local-user "$GPG_KEY_ID" \ - --detach-sign --armor --output "${CHART_FILE}.prov" "$CHART_FILE" - fi + --passphrase-file /tmp/passphrase.txt done - # Clean up passphrase file rm -f /tmp/passphrase.txt - - # List generated files - echo "Generated files:" - ls -la *.tgz *.prov 2>/dev/null || echo "No chart files found" - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' @@ -158,24 +75,20 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Use the same RSA key for verification (handle both armored and base64) + # Import key for verification SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then echo "$SECRET_CONTENT" | gpg --batch --import else - echo "$SECRET_CONTENT" | tr -d ' \n\r\t' > verify.key.b64 - base64 -d verify.key.b64 2>/dev/null | gpg --batch --import - rm -f verify.key.b64 + echo "$SECRET_CONTENT" | tr -d ' \n\r\t' | base64 -d | gpg --batch --import fi gpg --batch --export > ~/.gnupg/pubring.gpg for chart in *.tgz; do - echo "🔍 Verifying $chart..." - helm verify "$chart" || { echo "❌ Verification failed for $chart"; exit 1; } + helm verify "$chart" done - echo "✅ All charts are properly signed and verified" - name: Create Release (Manual trigger only) if: github.event_name == 'workflow_dispatch' From e8f225d28088f59685f0b15610c80c4b1e43f426 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 12:39:17 +0200 Subject: [PATCH 21/31] refactor: streamline GPG key handling in chart release workflow --- .github/workflows/chart-release.yml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 8659663c..15207ee4 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -31,30 +31,20 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Handle both raw armored keys and base64 encoded keys SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then - echo "$SECRET_CONTENT" > private.key + echo "$SECRET_CONTENT" | gpg --batch --import else - echo "$SECRET_CONTENT" | tr -d ' \n\r\t' > private.key.b64 - base64 -d private.key.b64 > private.key 2>/dev/null - rm -f private.key.b64 + echo "$SECRET_CONTENT" | tr -d ' \n\r\t' | base64 -d | gpg --batch --import fi - # Import and export to legacy GPG format for Helm compatibility - gpg --batch --import private.key gpg --batch --export > ~/.gnupg/pubring.gpg echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg - - rm -f private.key - name: Package and Sign Charts run: | - # Get the key name for Helm KEY_NAME=$(gpg --list-secret-keys --with-colons "$GPG_KEY_ID" | grep "^uid" | head -1 | cut -d: -f10) - - # Create passphrase file for Helm echo "$GPG_PASSPHRASE" > /tmp/passphrase.txt chmod 600 /tmp/passphrase.txt @@ -75,7 +65,6 @@ jobs: chmod 700 ~/.gnupg echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf - # Import key for verification SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then @@ -109,4 +98,4 @@ jobs: if: always() run: | gpg --batch --yes --delete-secret-keys "$GPG_KEY_ID" 2>/dev/null || true - gpg --batch --yes --delete-keys "$GPG_KEY_ID" 2>/dev/null || true \ No newline at end of file + gpg --batch --yes --delete-keys "$GPG_KEY_ID" 2>/dev/null || true From b2e969e984b1d60e121fd5f3a06f4fb3679d9a06 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 17:55:30 +0200 Subject: [PATCH 22/31] chore: use exivity chart releaser --- .github/workflows/chart-release.yml | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 15207ee4..c1137bb3 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -48,15 +48,26 @@ jobs: echo "$GPG_PASSPHRASE" > /tmp/passphrase.txt chmod 600 /tmp/passphrase.txt + # Create .cr-release-packages directory for chart-releaser-action + mkdir -p .cr-release-packages + for chart_dir in charts/*/; do [ -f "$chart_dir/Chart.yaml" ] || continue + echo "📦 Packaging and signing chart: $chart_dir" + + # Package and sign chart in the .cr-release-packages directory helm package --sign "$chart_dir" \ --key "$KEY_NAME" \ --keyring ~/.gnupg/secring.gpg \ - --passphrase-file /tmp/passphrase.txt + --passphrase-file /tmp/passphrase.txt \ + --destination .cr-release-packages done rm -f /tmp/passphrase.txt + + # List created packages for verification + echo "📋 Created signed packages:" + ls -la .cr-release-packages/ - name: Validate Signed Charts (PR only) if: github.event_name == 'pull_request' @@ -75,24 +86,19 @@ jobs: gpg --batch --export > ~/.gnupg/pubring.gpg - for chart in *.tgz; do + # Validate charts from the .cr-release-packages directory + for chart in .cr-release-packages/*.tgz; do + [ -f "$chart" ] || continue + echo "🔍 Verifying $chart..." helm verify "$chart" done + echo "✅ All charts are properly signed and verified" - - name: Create Release (Manual trigger only) + - name: Run chart-releaser if: github.event_name == 'workflow_dispatch' - run: | - CHART_VERSION=$(helm show chart charts/exivity/ | grep '^version:' | awk '{print $2}') - RELEASE_TAG="exivity-$CHART_VERSION" - - gpg --export --armor "$GPG_KEY_ID" > signing-key.asc - - gh release create "$RELEASE_TAG" \ - --title "Exivity Helm Chart $CHART_VERSION" \ - --notes "Signed Helm chart release" \ - *.tgz *.prov signing-key.asc + uses: exivity/chart-releaser-action@v1.1.0 env: - GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} + CR_TOKEN: "${{ secrets.GH_BOT_TOKEN }}" - name: Cleanup if: always() From 095fcb4dc2775835f474cf9994bc056857022532 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Wed, 25 Jun 2025 17:56:57 +0200 Subject: [PATCH 23/31] refactor: enhance Makefile with sign and validate package --- Makefile | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c7480dc2..53cdeafa 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,25 @@ -# Constants +# Makefile — Exivity Helm Charts: Deployment + Release Testing + +# 🏗️ Constants NFS_STORAGE_CLASS := nfs-client NFS_CHART_VERSION := 1.8.0 - INGRESS_HOSTNAME := exivity.local - HELM_TIMEOUT := 10m +# 🗝️ Dummy secrets for release workflow testing +GPG_KEY_ID ?= EXIVITY123TEST +GPG_PASSPHRASE ?= test1234 +HELM_RSA_PRIVATE_KEY ?= LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpFeGl2aXR5IFRlc3QgS2V5IDx0ZXN0QGV4aXZpdHkuY29tPgotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ== + +# 🔍 Variables for chart packaging +CHART_DIRS := $(shell find charts -maxdepth 1 -mindepth 1 -type d 2>/dev/null || echo "") +TGZ_FILES := $(patsubst charts/%,%.tgz,$(CHART_DIRS)) + + +# ===================================================================== +# 🚀 MINIKUBE DEPLOYMENT TARGETS +# ===================================================================== + # Define Minikube start with a specific driver minikube-start: @minikube start --memory 8192 --cpus 2 @@ -70,5 +84,60 @@ test: lint: @helm lint charts/exivity -# Makefile targets -.PHONY: minikube-start minikube-delete deploy-charts deploy-exivity-chart deploy-nfs-chart install-python-deps test + + +# --------------------------------------------------------------------- + + + +# ===================================================================== +# 🧪 RELEASE WORKFLOW TEST +# ===================================================================== + +# 🎁 Package every chart in charts/* → -.tgz +package-charts: $(TGZ_FILES) + +%.tgz: + @echo "📦 Helm-packaging $@" + @CHART_NAME=$(basename $@); \ + if [ -d "charts/$$CHART_NAME" ]; then \ + helm package "charts/$$CHART_NAME" > /dev/null 2>&1; \ + else \ + echo "⚠️ Chart directory charts/$$CHART_NAME not found"; \ + fi + +# 🔏 Forge dummy .prov files so downstream scripts still work +package-sign: + @echo "🔖 Creating fake .prov signature files (no GPG keys used)" + @if ls *.tgz >/dev/null 2>&1; then \ + for tgz in *.tgz; do \ + echo "-----BEGIN PGP SIGNATURE-----" > "$$tgz.prov"; \ + echo "Version: GnuPG v2" >> "$$tgz.prov"; \ + echo "" >> "$$tgz.prov"; \ + echo "Fake signature for testing purposes only" >> "$$tgz.prov"; \ + echo "Chart: $$tgz" >> "$$tgz.prov"; \ + echo "Key ID: $(GPG_KEY_ID)" >> "$$tgz.prov"; \ + echo "Passphrase: $(GPG_PASSPHRASE)" >> "$$tgz.prov"; \ + echo "-----END PGP SIGNATURE-----" >> "$$tgz.prov"; \ + echo " ✅ Created $$tgz.prov"; \ + done; \ + else \ + echo " ⚠️ No .tgz files found to sign"; \ + fi + +# ✅ Stubbed validation step — we deliberately *skip* helm verify +package-validate: + @echo "✅ Validation stub → skipping 'helm verify' because using fake signatures" + @echo "📋 Generated files:" + @ls -la *.tgz *.prov 2>/dev/null || echo " (no files found)" + +# 🧹 Clean up build artifacts +clean-release: + @echo "🧹 Removing generated .tgz/.prov files" + @rm -f *.tgz *.prov fake-signing-key.asc || true + +# 📖 Makefile targets + +.PHONY: minikube-start minikube-delete deploy-charts deploy-exivity-chart deploy-nfs-chart \ + install-python-deps test lint clean-release package-charts package-sign \ + validate-release From b36fc09b4afebeebb9ce064e54b8aab887e853bd Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 10:17:45 +0200 Subject: [PATCH 24/31] chore: simplify GPG key import and streamline chart packaging process --- .github/workflows/chart-release.yml | 41 +++++++++-------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index c1137bb3..dbf0f85d 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -33,11 +33,7 @@ jobs: SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" - if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then - echo "$SECRET_CONTENT" | gpg --batch --import - else - echo "$SECRET_CONTENT" | tr -d ' \n\r\t' | base64 -d | gpg --batch --import - fi + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | gpg --batch --import gpg --batch --export > ~/.gnupg/pubring.gpg echo "$GPG_PASSPHRASE" | gpg --batch --passphrase-fd 0 --export-secret-keys > ~/.gnupg/secring.gpg @@ -51,22 +47,17 @@ jobs: # Create .cr-release-packages directory for chart-releaser-action mkdir -p .cr-release-packages - for chart_dir in charts/*/; do - [ -f "$chart_dir/Chart.yaml" ] || continue - echo "📦 Packaging and signing chart: $chart_dir" - - # Package and sign chart in the .cr-release-packages directory - helm package --sign "$chart_dir" \ - --key "$KEY_NAME" \ - --keyring ~/.gnupg/secring.gpg \ - --passphrase-file /tmp/passphrase.txt \ - --destination .cr-release-packages - done + chart_dir=charts/exivity + helm package --sign "$chart_dir" \ + --key "$KEY_NAME" \ + --keyring ~/.gnupg/secring.gpg \ + --passphrase-file /tmp/passphrase.txt \ + --destination .cr-release-packages rm -f /tmp/passphrase.txt # List created packages for verification - echo "📋 Created signed packages:" + echo "✅ Created signed packages:" ls -la .cr-release-packages/ - name: Validate Signed Charts (PR only) @@ -78,21 +69,13 @@ jobs: SECRET_CONTENT="${{ secrets.HELM_RSA_PRIVATE_KEY }}" - if [[ "$SECRET_CONTENT" == *"-----BEGIN PGP PRIVATE KEY BLOCK-----"* ]]; then - echo "$SECRET_CONTENT" | gpg --batch --import - else - echo "$SECRET_CONTENT" | tr -d ' \n\r\t' | base64 -d | gpg --batch --import - fi - + echo "${{ secrets.HELM_RSA_PRIVATE_KEY }}" | gpg --batch --import gpg --batch --export > ~/.gnupg/pubring.gpg # Validate charts from the .cr-release-packages directory - for chart in .cr-release-packages/*.tgz; do - [ -f "$chart" ] || continue - echo "🔍 Verifying $chart..." - helm verify "$chart" - done - echo "✅ All charts are properly signed and verified" + find .cr-release-packages -maxdepth 1 -type f -name '*.tgz' -print -exec helm verify {} \; + + echo "✅ Charts are properly signed and verified." - name: Run chart-releaser if: github.event_name == 'workflow_dispatch' From 391b5c14af6763c7c5f2a42fff2273911eaab659 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 10:32:03 +0200 Subject: [PATCH 25/31] chore: clean up Makefile comments --- Makefile | 82 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 53cdeafa..a949d651 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,23 @@ # Makefile — Exivity Helm Charts: Deployment + Release Testing -# 🏗️ Constants +# Constants NFS_STORAGE_CLASS := nfs-client NFS_CHART_VERSION := 1.8.0 INGRESS_HOSTNAME := exivity.local HELM_TIMEOUT := 10m -# 🗝️ Dummy secrets for release workflow testing +# Dummy secrets for release workflow testing GPG_KEY_ID ?= EXIVITY123TEST GPG_PASSPHRASE ?= test1234 HELM_RSA_PRIVATE_KEY ?= LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpFeGl2aXR5IFRlc3QgS2V5IDx0ZXN0QGV4aXZpdHkuY29tPgotLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQ== -# 🔍 Variables for chart packaging +# Variables for chart packaging CHART_DIRS := $(shell find charts -maxdepth 1 -mindepth 1 -type d 2>/dev/null || echo "") TGZ_FILES := $(patsubst charts/%,%.tgz,$(CHART_DIRS)) # ===================================================================== -# 🚀 MINIKUBE DEPLOYMENT TARGETS +# MINIKUBE DEPLOYMENT TARGETS # ===================================================================== # Define Minikube start with a specific driver @@ -83,34 +83,30 @@ test: # Lint Helm chart lint: @helm lint charts/exivity - - - -# --------------------------------------------------------------------- - - - + # ===================================================================== -# 🧪 RELEASE WORKFLOW TEST +# RELEASE WORKFLOW TEST # ===================================================================== -# 🎁 Package every chart in charts/* → -.tgz -package-charts: $(TGZ_FILES) - -%.tgz: - @echo "📦 Helm-packaging $@" - @CHART_NAME=$(basename $@); \ - if [ -d "charts/$$CHART_NAME" ]; then \ - helm package "charts/$$CHART_NAME" > /dev/null 2>&1; \ +# Package exivity charts +package-charts: + @echo "📦 Simulating GitHub Actions 'Package and Sign Charts' step" + @echo "Creating .cr-release-packages directory for chart-releaser-action" + @mkdir -p .cr-release-packages + @echo "Packaging chart: charts/exivity" + @if [ -d "charts/exivity" ]; then \ + helm package "charts/exivity" --destination .cr-release-packages > /dev/null 2>&1; \ + echo "✅ Created signed packages:"; \ + ls -la .cr-release-packages/; \ else \ - echo "⚠️ Chart directory charts/$$CHART_NAME not found"; \ + echo "❌ Chart directory charts/exivity not found"; \ fi -# 🔏 Forge dummy .prov files so downstream scripts still work +# Sign the packaged charts package-sign: - @echo "🔖 Creating fake .prov signature files (no GPG keys used)" - @if ls *.tgz >/dev/null 2>&1; then \ - for tgz in *.tgz; do \ + @echo "🔖 Simulating GPG signing (creating fake .prov files)" + @if ls .cr-release-packages/*.tgz >/dev/null 2>&1; then \ + for tgz in .cr-release-packages/*.tgz; do \ echo "-----BEGIN PGP SIGNATURE-----" > "$$tgz.prov"; \ echo "Version: GnuPG v2" >> "$$tgz.prov"; \ echo "" >> "$$tgz.prov"; \ @@ -121,23 +117,35 @@ package-sign: echo "-----END PGP SIGNATURE-----" >> "$$tgz.prov"; \ echo " ✅ Created $$tgz.prov"; \ done; \ + echo "📋 Updated packages with signatures:"; \ + ls -la .cr-release-packages/; \ else \ - echo " ⚠️ No .tgz files found to sign"; \ + echo " ⚠️ No .tgz files found in .cr-release-packages/"; \ fi -# ✅ Stubbed validation step — we deliberately *skip* helm verify +# Validate signed charts package-validate: - @echo "✅ Validation stub → skipping 'helm verify' because using fake signatures" - @echo "📋 Generated files:" - @ls -la *.tgz *.prov 2>/dev/null || echo " (no files found)" + @echo "✅ Simulating GitHub Actions 'Validate Signed Charts' step" + @echo "🔍 Finding and validating charts from .cr-release-packages directory:" + @if [ -d ".cr-release-packages" ]; then \ + find .cr-release-packages -maxdepth 1 -type f -name '*.tgz' -print | while read chart; do \ + echo "� Would run: helm verify $$chart"; \ + done; \ + if ls .cr-release-packages/*.tgz >/dev/null 2>&1; then \ + echo "✅ Charts are properly signed and verified."; \ + else \ + echo "⚠️ No .tgz files found to validate"; \ + fi; \ + else \ + echo "❌ .cr-release-packages directory not found"; \ + fi + -# 🧹 Clean up build artifacts +# Clean up build artifacts clean-release: - @echo "🧹 Removing generated .tgz/.prov files" + @echo "🧹 Removing generated files and .cr-release-packages directory" @rm -f *.tgz *.prov fake-signing-key.asc || true + @rm -rf .cr-release-packages || true -# 📖 Makefile targets - -.PHONY: minikube-start minikube-delete deploy-charts deploy-exivity-chart deploy-nfs-chart \ - install-python-deps test lint clean-release package-charts package-sign \ - validate-release +# Makefile targets +.PHONY: minikube-start minikube-delete deploy-charts deploy-exivity-chart deploy-nfs-chart install-python-deps test lint clean-release package-charts package-sign package-validate From a3fc236afa05b17642968e17ddc8eac6da479a2e Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 10:34:37 +0200 Subject: [PATCH 26/31] chore: remove pull_request trigger and streamline chart-releaser execution --- .github/workflows/chart-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index dbf0f85d..28f07ade 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -78,7 +78,6 @@ jobs: echo "✅ Charts are properly signed and verified." - name: Run chart-releaser - if: github.event_name == 'workflow_dispatch' uses: exivity/chart-releaser-action@v1.1.0 env: CR_TOKEN: "${{ secrets.GH_BOT_TOKEN }}" From f2a4df881fb36b3c32efe56f8dcda541af716f91 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 10:41:39 +0200 Subject: [PATCH 27/31] chore: add Bitnami helm repository to chart release workflow --- .github/workflows/chart-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 28f07ade..edec4fc3 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -24,6 +24,7 @@ jobs: run: | git config user.name "$GITHUB_ACTOR" git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + helm repo add bitnami https://charts.bitnami.com/bitnami - name: Configure GPG run: | From 7f6941b17c9e67f957c813c5f297af264dfe9771 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 11:05:03 +0200 Subject: [PATCH 28/31] chore: update chart-releaser step to clarify manual dispatch requirement --- .github/workflows/chart-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index edec4fc3..b61c4472 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -78,7 +78,8 @@ jobs: echo "✅ Charts are properly signed and verified." - - name: Run chart-releaser + - name: Run chart-releaser (release only on manual dispatch) + if: github.event_name == 'workflow_dispatch' uses: exivity/chart-releaser-action@v1.1.0 env: CR_TOKEN: "${{ secrets.GH_BOT_TOKEN }}" From f496716ee0e70b290ea435112a4e85bda3864eac Mon Sep 17 00:00:00 2001 From: Xiang YS <74994910+xiangyisss@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:09:16 +0200 Subject: [PATCH 29/31] update .github/workflows/chart-release.yml Co-authored-by: Steffen Exler --- .github/workflows/chart-release.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index b61c4472..5cfb8c75 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -2,10 +2,6 @@ name: Release Charts on: workflow_dispatch: - pull_request: - paths: - - 'charts/**' - - '.github/workflows/chart-release.yml' jobs: helm-release: From f66d8098d4a52f6841ac0d70b342fbda6975e458 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 14:45:27 +0200 Subject: [PATCH 30/31] chore: release only run on tag push --- .github/workflows/chart-release.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 5cfb8c75..5f178d52 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -2,6 +2,13 @@ name: Release Charts on: workflow_dispatch: + push: + branches: ["main"] + tags: + - "exivity-*" + paths: + - 'charts/**' # Any file under charts/ + - '.github/workflows/chart-release.yml' jobs: helm-release: @@ -74,9 +81,11 @@ jobs: echo "✅ Charts are properly signed and verified." - - name: Run chart-releaser (release only on manual dispatch) - if: github.event_name == 'workflow_dispatch' - uses: exivity/chart-releaser-action@v1.1.0 + - name: Run chart-releaser (release only on tag push) + if: startsWith(github.ref, 'refs/tags/') + uses: exivity/chart-releaser-action@v1.7.0 + with: + skip_packaging: true env: CR_TOKEN: "${{ secrets.GH_BOT_TOKEN }}" From cd0e78dab164b2b7d660fb3b2bb83116e9a7ac87 Mon Sep 17 00:00:00 2001 From: xiangyisss Date: Thu, 26 Jun 2025 15:00:11 +0200 Subject: [PATCH 31/31] chore: remove redundant code --- .github/workflows/chart-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 5f178d52..1313807c 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -64,8 +64,7 @@ jobs: echo "✅ Created signed packages:" ls -la .cr-release-packages/ - - name: Validate Signed Charts (PR only) - if: github.event_name == 'pull_request' + - name: Validate Signed Charts run: | mkdir -p ~/.gnupg chmod 700 ~/.gnupg