chore: remove ggscout schemas from this repo and update flow to use m… #162
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
name: Validate Helm Chart Examples | |
on: | |
push: | |
branches: [ main ] | |
paths: | |
- 'charts/ggscout/**' | |
pull_request: | |
branches: [ main ] | |
paths: | |
- 'charts/ggscout/**' | |
workflow_dispatch: | |
jobs: | |
find-examples: | |
runs-on: ubuntu-latest | |
outputs: | |
examples: ${{ steps.set-matrix.outputs.examples }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Find all examples and create matrix | |
id: set-matrix | |
run: | | |
# Find all example directories | |
ALL_EXAMPLES=$(find charts/ggscout/examples -maxdepth 1 -mindepth 1 -type d -exec basename {} \;) | |
# Create JSON array for GitHub Actions matrix | |
echo "examples=$(echo "$ALL_EXAMPLES" | jq -R -s -c 'split("\n") | map(select(length > 0))')" >> $GITHUB_OUTPUT | |
echo "Found examples: $ALL_EXAMPLES" | |
lint-examples: | |
needs: find-examples | |
runs-on: ubuntu-latest | |
strategy: | |
# Run all examples in parallel | |
fail-fast: false | |
matrix: | |
example: ${{ fromJson(needs.find-examples.outputs.examples) }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Set up Helm | |
uses: azure/setup-helm@v3 | |
with: | |
version: 'latest' | |
- name: Install yq | |
run: | | |
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq | |
sudo chmod +x /usr/bin/yq | |
- name: Lint chart example - ${{ matrix.example }} | |
run: | | |
echo "🔍 Linting example: ${{ matrix.example }}" | |
# Create values-ci.yaml for linting | |
echo "Creating values-ci.yaml for ${{ matrix.example }}" | |
cp "charts/ggscout/examples/${{ matrix.example }}/values.yaml" "charts/ggscout/examples/${{ matrix.example }}/values-ci.yaml" | |
# Check if secret.yaml exists and apply values to values-ci.yaml | |
if [ -f "charts/ggscout/examples/${{ matrix.example }}/secret.yaml" ]; then | |
echo "Found secret.yaml, using it for values replacement" | |
# Create a temporary file to store environment variables | |
ENV_FILE="charts/ggscout/examples/${{ matrix.example }}/.env.tmp" | |
touch $ENV_FILE | |
# Extract keys and values from secret.yaml and write to env file | |
yq '.stringData | to_entries | .[] | .key + "=" + .value' "charts/ggscout/examples/${{ matrix.example }}/secret.yaml" > $ENV_FILE | |
# Process values-ci.yaml and replace ${VAR} patterns with actual values from secret.yaml | |
# Read env file line by line | |
while IFS= read -r line; do | |
# Extract key and value | |
KEY=$(echo $line | cut -d= -f1) | |
VALUE=$(echo $line | cut -d= -f2-) | |
# Remove quotes if present | |
VALUE="${VALUE%\"}" | |
VALUE="${VALUE#\"}" | |
VALUE="${VALUE%\'}" | |
VALUE="${VALUE#\'}" | |
# Replace ${KEY} with VALUE in values-ci.yaml | |
sed -i.bak "s|\${$KEY}|$VALUE|g" "charts/ggscout/examples/${{ matrix.example }}/values-ci.yaml" | |
rm "charts/ggscout/examples/${{ matrix.example }}/values-ci.yaml.bak" | |
done < $ENV_FILE | |
# Remove temporary env file | |
rm $ENV_FILE | |
fi | |
# Run helm lint | |
if ! helm lint charts/ggscout -f "charts/ggscout/examples/${{ matrix.example }}/values-ci.yaml"; then | |
echo "❌ Helm lint failed for ${{ matrix.example }}" | |
exit 1 | |
else | |
echo "✅ Helm lint passed for ${{ matrix.example }}" | |
fi | |
# Clean up the temporary values-ci.yaml file | |
rm "charts/ggscout/examples/${{ matrix.example }}/values-ci.yaml" | |
validate-examples: | |
needs: lint-examples | |
runs-on: ubuntu-latest | |
strategy: | |
# Fail-fast set to false ensures all examples are tested even if one fails | |
fail-fast: false | |
matrix: | |
example-group: | |
- secret_manager_group_1: ["akeyless", "conjurcloud", "hashicorpvault", "azurekeyvault"] | |
- secret_manager_group_2: ["delinea", "gcpsecretmanager", "awssecretsmanager"] # TODO: add fetch-only | |
# - consumers: ["k8s_incluster", "k8s_kubeconfigfile", "gitlabci"] | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Set up Helm | |
uses: azure/setup-helm@v3 | |
with: | |
version: 'latest' | |
# Create a kind cluster for actual deployment testing | |
- name: Create kind cluster | |
uses: helm/[email protected] | |
with: | |
cluster_name: ggscout-test | |
wait: 120s | |
- name: Install kubectl | |
uses: azure/setup-kubectl@v3 | |
with: | |
version: 'latest' | |
- name: Install yq | |
run: | | |
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq | |
sudo chmod +x /usr/bin/yq | |
# Get the example directories from the matrix | |
- name: Set example directories | |
id: set-examples | |
run: | | |
# Parse the JSON object from matrix | |
GROUP_NAME=$(jq -n -r --argjson examples '${{ toJSON(matrix.example-group) }}' '$examples | keys[0]') | |
DIRS=$(jq -n -r --argjson examples '${{ toJSON(matrix.example-group) }}' --arg group "$GROUP_NAME" '$examples[$group] | .[]') | |
echo "group=$GROUP_NAME" >> $GITHUB_OUTPUT | |
echo "directories<<EOF" >> $GITHUB_OUTPUT | |
echo "$DIRS" >> $GITHUB_OUTPUT | |
echo "EOF" >> $GITHUB_OUTPUT | |
# Create test namespace | |
- name: Create test namespace | |
run: | | |
kubectl create namespace ggscout-test | |
# Create GCP SA Key Secret in Kubernetes | |
- name: Create GCP SA Key Secret | |
run: | | |
echo "Creating GCP service account key secret..." | |
# Decode the Base64 encoded secret and create a Kubernetes secret | |
echo "${{ secrets.GCP_SA_KEY }}" | base64 --decode > gcp_key.json | |
kubectl create secret generic gcp-key-secret --namespace ggscout-test --from-file=gcp_key.json | |
echo "✅ Secret gcp-key-secret created with GCP credentials" | |
# Deploy and validate each example in the cluster | |
- name: Deploy and validate examples | |
env: | |
GITGUARDIAN_API_URL: ${{ secrets.GITGUARDIAN_API_URL }} | |
GITLAB_URL: ${{ secrets.GITLAB_URL }} | |
HASHICORP_VAULT_URL: ${{ secrets.HASHICORP_VAULT_URL }} | |
run: | | |
GROUP="${{ steps.set-examples.outputs.group }}" | |
DIRS="${{ steps.set-examples.outputs.directories }}" | |
for example in $DIRS; do | |
echo "🔍 Validating example: $example" | |
release_name="ggscout-test-${example}-${GITHUB_SHA::7}" | |
# Create values-ci.yaml with the correct endpoint URL | |
# This is needed to pass the helm lint step which checks the schema | |
echo "Creating values-ci.yaml for $example" | |
cp "charts/ggscout/examples/$example/values.yaml" "charts/ggscout/examples/$example/values-ci.yaml" | |
# Ensure the endpoint is properly set with the GitHub secret value | |
yq -i '.inventory.config.gitguardian.endpoint = env(GITGUARDIAN_API_URL)' "charts/ggscout/examples/$example/values-ci.yaml" | |
# Replace HashiCorp Vault URL environment variable for validation | |
if [[ "$example" == "hashicorpvault" || "$example" == "fetch-only" ]]; then | |
echo "Replacing HashiCorp Vault URL for validation with \"$HASHICORP_VAULT_URL\"" | |
yq -i '.inventory.config.sources.hashicorpvault.vault_address = env(HASHICORP_VAULT_URL)' "charts/ggscout/examples/$example/values-ci.yaml" | |
fi | |
if [[ "$example" == "gitlabci" ]]; then | |
echo "Replacing GitLab URL for validation with \"$GITLAB_URL\"" | |
yq -i '.inventory.config.sources.gitlab.url = env(GITLAB_URL)' "charts/ggscout/examples/$example/values-ci.yaml" | |
fi | |
# First run basic helm lint for quick failures | |
echo "🔍 Running helm lint for $example" | |
if ! helm lint charts/ggscout -f "charts/ggscout/examples/$example/values-ci.yaml"; then | |
echo "❌ Helm lint failed for $example" | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
# Install the Helm chart to the cluster | |
echo "🚀 Installing $example to test cluster" | |
# For fetch-only example, create a special configuration to fix permission issues | |
if [[ "$example" == "fetch-only" ]]; then | |
echo "📋 Creating special configuration for fetch-only example to fix permission issues" | |
# Create a complete values file with all necessary overrides | |
cp "charts/ggscout/examples/$example/values-ci.yaml" "charts/ggscout/examples/$example/values-fixed.yaml" | |
# Modify the new values file to use emptyDir instead of hostPath | |
yq -i '.volumes[0].hostPath = null' "charts/ggscout/examples/$example/values-fixed.yaml" | |
yq -i '.volumes[0].emptyDir = {}' "charts/ggscout/examples/$example/values-fixed.yaml" | |
# Install with the fixed values file and appropriate security context | |
if ! helm install $release_name charts/ggscout \ | |
--namespace ggscout-test \ | |
-f "charts/ggscout/examples/$example/values-fixed.yaml" \ | |
--set "podSecurityContext.fsGroup=65532" \ | |
--set "podSecurityContext.runAsUser=65532" \ | |
--set "podSecurityContext.runAsNonRoot=true" \ | |
--wait --timeout 3m; then | |
echo "❌ Failed to install $example to the cluster" | |
kubectl get pods -n ggscout-test -l "app.kubernetes.io/instance=$release_name" | |
kubectl get events -n ggscout-test | |
kubectl describe pod -n ggscout-test -l "app.kubernetes.io/instance=$release_name" | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
rm "charts/ggscout/examples/$example/values-fixed.yaml" | |
exit 1 | |
fi | |
else | |
# Regular installation for other examples | |
if ! helm install $release_name charts/ggscout \ | |
--namespace ggscout-test \ | |
-f "charts/ggscout/examples/$example/values-ci.yaml" \ | |
--wait --timeout 3m; then | |
echo "❌ Failed to install $example to the cluster" | |
kubectl get pods -n ggscout-test -l "app.kubernetes.io/instance=$release_name" | |
kubectl get events -n ggscout-test | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
fi | |
# Get all CronJobs for this release | |
CRONJOBS=$(kubectl get cronjobs -n ggscout-test -l "app.kubernetes.io/instance=$release_name" -o name) | |
if [ -z "$CRONJOBS" ]; then | |
echo "⚠️ No CronJobs found for $example. Checking if this is expected..." | |
# Check if jobs are enabled in the values file | |
FETCH_ENABLED=$(grep -A5 "fetch:" "charts/ggscout/examples/$example/values.yaml" | grep "enabled:" | grep "true" || echo "") | |
SYNC_ENABLED=$(grep -A5 "sync:" "charts/ggscout/examples/$example/values.yaml" | grep "enabled:" | grep "true" || echo "") | |
if [ -n "$FETCH_ENABLED" ] || [ -n "$SYNC_ENABLED" ]; then | |
echo "❌ Expected CronJobs but none were found" | |
kubectl get all -n ggscout-test | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
else | |
echo "ℹ️ No CronJobs expected for this example, continuing validation" | |
fi | |
else | |
echo "Found CronJobs: $CRONJOBS" | |
# Check if the secret already exists before creating it | |
echo "🔍 Checking if ggscout-secrets secret already exists" | |
if ! kubectl get secret ggscout-secrets --namespace ggscout-test &>/dev/null; then | |
# Create the secret only if it doesn't exist | |
SECRET_CMD="kubectl create secret generic ggscout-secrets --namespace ggscout-test" | |
# Add all GitHub secrets to the command | |
for SECRET_NAME in $(echo '${{ toJSON(secrets) }}' | jq -r 'keys[]'); do | |
SECRET_VALUE=$(echo '${{ toJSON(secrets) }}' | jq -r --arg name "$SECRET_NAME" '.[$name]') | |
SECRET_CMD="$SECRET_CMD --from-literal=$SECRET_NAME=$SECRET_VALUE" | |
done | |
# Execute the command | |
eval "$SECRET_CMD" | |
else | |
echo "ℹ️ ggscout-secrets secret already exists, skipping creation" | |
fi | |
# Manually trigger each CronJob by creating a Job from it | |
for cronjob in $CRONJOBS; do | |
CRONJOB_NAME=$(echo $cronjob | cut -d'/' -f2) | |
JOB_NAME="${CRONJOB_NAME}-$(date +%s)" | |
echo "🔄 Manually triggering CronJob $CRONJOB_NAME as Job $JOB_NAME" | |
# Create a Job from the CronJob spec | |
kubectl create job --from=cronjob/$CRONJOB_NAME $JOB_NAME -n ggscout-test | |
# Wait for job to complete | |
echo "⏳ Waiting for job $JOB_NAME to complete" | |
# Set timeout and interval for checking job status | |
TIMEOUT=180 | |
INTERVAL=10 | |
ELAPSED=0 | |
# Loop until job completes or times out | |
while [ $ELAPSED -lt $TIMEOUT ]; do | |
# Check if job completed successfully | |
STATUS=$(kubectl get job/$JOB_NAME -n ggscout-test -o jsonpath='{.status.conditions[?(@.type=="Complete")].status}') | |
if [ "$STATUS" == "True" ]; then | |
echo "✅ Job $JOB_NAME completed successfully" | |
kubectl logs job/$JOB_NAME -n ggscout-test | |
break | |
fi | |
# Check if job failed | |
FAILED=$(kubectl get job/$JOB_NAME -n ggscout-test -o jsonpath='{.status.conditions[?(@.type=="Failed")].status}') | |
if [ "$FAILED" == "True" ]; then | |
echo "❌ Job $JOB_NAME failed" | |
kubectl logs job/$JOB_NAME -n ggscout-test || true | |
kubectl describe job/$JOB_NAME -n ggscout-test | |
kubectl describe pods -n ggscout-test -l "job-name=$JOB_NAME" | |
kubectl get pods -n ggscout-test -l "job-name=$JOB_NAME" -o yaml | |
# Debug - Get the pod name and execute commands to check files | |
POD_NAME=$(kubectl get pods -n ggscout-test -l "job-name=$JOB_NAME" -o jsonpath='{.items[0].metadata.name}') | |
if [ -n "$POD_NAME" ]; then | |
echo "📂 Debugging file locations in pod $POD_NAME" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "ls -la / || echo 'Cannot list root'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "ls -la /app || echo 'No /app directory'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "ls -la /etc || echo 'Cannot list /etc'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "ls -la /etc/inventory || echo 'No /etc/inventory directory'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "cat /etc/inventory/config.yml || echo 'Cannot read config'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "find / -name gcp_key.json 2>/dev/null || echo 'gcp_key.json not found'" | |
kubectl exec -n ggscout-test $POD_NAME -- sh -c "find / -name '*.json' 2>/dev/null || echo 'No JSON files found'" | |
fi | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
# Show current logs while waiting | |
echo "📋 Current logs for job $JOB_NAME (elapsed: ${ELAPSED}s):" | |
kubectl logs job/$JOB_NAME -n ggscout-test --tail=10 || echo "No logs available yet" | |
# Wait before checking again | |
sleep $INTERVAL | |
ELAPSED=$((ELAPSED + INTERVAL)) | |
echo "⏳ Still waiting... ($ELAPSED/$TIMEOUT sec)" | |
done | |
# Check if we timed out | |
if [ $ELAPSED -ge $TIMEOUT ]; then | |
echo "❌ Job $JOB_NAME timed out" | |
kubectl logs job/$JOB_NAME -n ggscout-test || true | |
kubectl describe job/$JOB_NAME -n ggscout-test | |
kubectl describe pods -n ggscout-test -l "job-name=$JOB_NAME" | |
kubectl get pods -n ggscout-test -l "job-name=$JOB_NAME" -o yaml | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
done | |
fi | |
# Wait for all jobs to complete | |
echo "⏳ Waiting for jobs to complete for $example" | |
# Get all jobs for this release | |
JOBS=$(kubectl get jobs -n ggscout-test -l "app.kubernetes.io/instance=$release_name" -o name) | |
if [ -z "$JOBS" ]; then | |
echo "⚠️ No jobs found for $example, skipping job completion check" | |
else | |
for job in $JOBS; do | |
echo "Checking job $job" | |
# Wait for job to complete (or fail) | |
TIMEOUT=300 | |
INTERVAL=10 | |
ELAPSED=0 | |
while [ $ELAPSED -lt $TIMEOUT ]; do | |
# Check if job completed successfully | |
STATUS=$(kubectl get $job -n ggscout-test -o jsonpath='{.status.conditions[?(@.type=="Complete")].status}') | |
if [ "$STATUS" == "True" ]; then | |
echo "✅ Job $job completed successfully" | |
break | |
fi | |
# Check if job failed | |
FAILED=$(kubectl get $job -n ggscout-test -o jsonpath='{.status.conditions[?(@.type=="Failed")].status}') | |
if [ "$FAILED" == "True" ]; then | |
echo "❌ Job $job failed" | |
kubectl logs $job -n ggscout-test | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
sleep $INTERVAL | |
ELAPSED=$((ELAPSED + INTERVAL)) | |
echo "Still waiting... ($ELAPSED sec)" | |
done | |
if [ $ELAPSED -ge $TIMEOUT ]; then | |
echo "❌ Timed out waiting for job $job to complete" | |
kubectl logs $job -n ggscout-test | |
helm uninstall $release_name --namespace ggscout-test || true | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
exit 1 | |
fi | |
done | |
fi | |
# Uninstall the release | |
helm uninstall $release_name --namespace ggscout-test | |
# Clean up the temporary values-ci.yaml file | |
rm "charts/ggscout/examples/$example/values-ci.yaml" | |
echo "✅ Example $example passed validation with successful job completion" | |
done | |
# Generate summary report | |
- name: Generate summary | |
run: | | |
GROUP="${{ steps.set-examples.outputs.group }}" | |
DIRS="${{ steps.set-examples.outputs.directories }}" | |
echo "## Helm Chart Validation Summary for $GROUP examples" >> $GITHUB_STEP_SUMMARY | |
echo "|Example|Status|" >> $GITHUB_STEP_SUMMARY | |
echo "|-------|------|" >> $GITHUB_STEP_SUMMARY | |
for example in $DIRS; do | |
echo "|$example|✅ Passed with job completion|" >> $GITHUB_STEP_SUMMARY | |
done |