fix: KMS-only CI secrets, remove GitHub secrets fallback

This commit is contained in:
Hanzo AI
2026-04-07 10:25:33 -07:00
parent 8bf7f4c659
commit 1c8b13260a
2 changed files with 223 additions and 28 deletions
+90 -23
View File
@@ -47,8 +47,6 @@ on:
default: "20"
description: "Node.js version for lint/test"
secrets:
TOKEN_GITHUB_CICD:
required: true
KMS_CLIENT_ID:
required: true
KMS_CLIENT_SECRET:
@@ -71,10 +69,42 @@ jobs:
with:
node-version: ${{ inputs.node_version }}
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Configure GHPR auth
run: |
echo "@zoo-labs:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.TOKEN_GITHUB_CICD }}" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ steps.kms.outputs.TOKEN_GITHUB_CICD }}" >> .npmrc
- name: Install dependencies
run: npm ci --ignore-scripts 2>/dev/null || npm install --ignore-scripts
@@ -103,32 +133,37 @@ jobs:
with:
fetch-depth: 1
- name: Fetch CI secrets from KMS
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.zoo.ngo"
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN=""
if [ -n "${KMS_CLIENT_ID}" ] && [ -n "${KMS_CLIENT_SECRET}" ]; then
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "$(jq -nc --arg cid "$KMS_CLIENT_ID" --arg cs "$KMS_CLIENT_SECRET" \
'{clientId: $cid, clientSecret: $cs}')" \
| jq -r '.accessToken' 2>/dev/null
)" || ACCESS_TOKEN=""
fi
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
if [ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ]; then
echo "::notice::Authenticated to KMS"
else
echo "::error::KMS auth failed"
exit 1
fi
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Compute metadata
id: meta
@@ -211,7 +246,7 @@ jobs:
${{ steps.meta.outputs.ghcr_image }}:v${{ steps.meta.outputs.version }}
${{ steps.meta.outputs.ghcr_image }}:${{ steps.meta.outputs.branch }}-${{ steps.meta.outputs.sha7 }}
build-args: |
NPM_TOKEN=${{ secrets.TOKEN_GITHUB_CICD }}
NPM_TOKEN=${{ steps.kms.outputs.TOKEN_GITHUB_CICD }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
@@ -222,10 +257,42 @@ jobs:
needs: [build-push]
if: needs.build-push.result == 'success' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
steps:
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Dispatch to universe
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.TOKEN_GITHUB_CICD }}
token: ${{ steps.kms.outputs.TOKEN_GITHUB_CICD }}
repository: zoo-labs/universe
event-type: service-built
client-payload: |
+133 -5
View File
@@ -131,10 +131,42 @@ jobs:
needs: resolve
if: needs.resolve.outputs.mode == 'deploy-single'
steps:
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- uses: actions/checkout@v4
with:
ref: ${{ needs.resolve.outputs.environment }}
token: ${{ secrets.TOKEN_GITHUB_CICD }}
token: ${{ steps.kms.outputs.TOKEN_GITHUB_CICD }}
- name: Update manifest
run: |
@@ -146,7 +178,7 @@ jobs:
- name: Create deploy PR (triggers E2E before merge)
env:
GH_TOKEN: ${{ secrets.TOKEN_GITHUB_CICD }}
GH_TOKEN: ${{ steps.kms.outputs.TOKEN_GITHUB_CICD }}
run: |
git config user.name "zoo-ci"
git config user.email "[email protected]"
@@ -193,10 +225,42 @@ jobs:
with:
ref: ${{ needs.resolve.outputs.environment }}
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
token: ${{ steps.kms.outputs.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Configure kubectl
run: doctl kubernetes cluster kubeconfig save "${{ env.CLUSTER }}"
@@ -239,10 +303,42 @@ jobs:
with:
ref: ${{ needs.resolve.outputs.environment }}
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
token: ${{ steps.kms.outputs.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Configure kubectl
run: doctl kubernetes cluster kubeconfig save "${{ env.CLUSTER }}"
@@ -276,10 +372,42 @@ jobs:
- name: Install Playwright
run: npx playwright install --with-deps chromium 2>/dev/null || true
- name: Fetch secrets from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
run: |
set -euo pipefail
KMS_URL="https://kms.main."
WORKSPACE="zoo-platform"
ACCESS_TOKEN="$(
curl -fsS --max-time 10 -X POST "${KMS_URL}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken'
)"
[ -n "${ACCESS_TOKEN}" ] && [ "${ACCESS_TOKEN}" != "null" ] || { echo "::error::KMS auth failed"; exit 1; }
fetch_secret() {
curl -fsS "${KMS_URL}/api/v3/secrets/raw/${1}?workspaceSlug=${WORKSPACE}&environment=prod&secretPath=/ci&viewSecretValue=true&include_imports=true" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq -r '.secret.secretValue'
}
for name in GCP_CREDENTIAL TOKEN_GITHUB_CICD DIGITALOCEAN_ACCESS_TOKEN; do
val="$(fetch_secret "$name" 2>/dev/null || echo "")"
[ -n "$val" ] && [ "$val" != "null" ] || continue
echo "::add-mask::${val}"
{ echo "${name}<<ENDOFSECRET"; echo "${val}"; echo "ENDOFSECRET"; } >> "$GITHUB_OUTPUT"
done
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
token: ${{ steps.kms.outputs.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Configure kubectl
run: doctl kubernetes cluster kubeconfig save "${{ env.CLUSTER }}"