name: CI TEST (Vault secrets) on: push: branches: [ main, master ] jobs: build: runs-on: [self-hosted, linux, docker] container: image: node:24.13-alpine3.22 options: --network host steps: - name: Checkout uses: https://gitea.nikitapozd.dev/actions/checkout@v6 - name: Pre-APK smoke (no installs) run: | set -eux echo "--- /etc/apk/repositories ---" cat /etc/apk/repositories || true echo "--- resolv.conf ---" cat /etc/resolv.conf || true echo "--- route ---" ip route || true echo "--- try download APKINDEX with busybox wget ---" wget -S -O /dev/null --timeout=10 --tries=1 \ https://dl-cdn.alpinelinux.org/alpine/v3.22/main/x86_64/APKINDEX.tar.gz - name: Bootstrap network tools run: | set -eux # wget/curl/ca-certificates + dns tools apk add --no-cache ca-certificates wget curl jq bind-tools busybox-extras update-ca-certificates || true - name: Network smoke test (verbose) run: | set -eux echo "=== IP / route ===" ip addr ip route echo "=== resolv.conf ===" cat /etc/resolv.conf || true echo "=== DNS (A/AAAA) ===" nslookup -type=A dl-cdn.alpinelinux.org || true nslookup -type=AAAA dl-cdn.alpinelinux.org || true echo "=== TCP 443 check ===" # busybox-extras дает nc nc -vz dl-cdn.alpinelinux.org 443 || true echo "=== HTTPS HEAD via curl (IPv4 forced) ===" curl -4 -vI --max-time 10 https://dl-cdn.alpinelinux.org/ || true echo "=== APKINDEX download via wget (IPv4 forced, debug) ===" # важное: именно APKINDEX, как в apk wget -4 --debug -S -O /dev/null --timeout=10 --tries=1 \ https://dl-cdn.alpinelinux.org/alpine/v3.22/main/x86_64/APKINDEX.tar.gz - name: APK update/add (verbose) run: | set -eux export APK_PROGRESS=plain # если тут зависнет — значит проблема точно на fetch layer apk update -v --no-progress apk add -v --no-cache curl jq - name: Get Keycloak access token from Gitea secrets env: KEYCLOAK_TOKEN_URL: ${{ secrets.KEYCLOAK_TOKEN_URL }} KEYCLOAK_CLIENT_ID: ${{ secrets.KEYCLOAK_CLIENT_ID }} KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }} run: | TOKEN_RESPONSE=$(curl -sS -X POST "$KEYCLOAK_TOKEN_URL" \ -d "grant_type=client_credentials" \ -d "client_id=$KEYCLOAK_CLIENT_ID" \ -d "client_secret=$KEYCLOAK_CLIENT_SECRET") ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token') if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then echo "ERROR: Failed to obtain access_token from Keycloak" echo "$TOKEN_RESPONSE" | jq . exit 1 fi # Не печатай токен в лог echo "ACCESS_TOKEN=$ACCESS_TOKEN" >> "$GITHUB_ENV" - name: Exchange Keycloak token for Vault token (auth/jwt/login) env: VAULT_ADDRESS: ${{ secrets.VAULT_ADDRESS }} VAULT_JWT_ROLE: ${{ secrets.VAULT_ROLE }} run: | LOGIN_RESPONSE=$(curl -sS -X POST "$VAULT_ADDRESS/v1/auth/jwt/login" \ -H "Content-Type: application/json" \ -d "{\"role\":\"$VAULT_JWT_ROLE\",\"jwt\":\"$ACCESS_TOKEN\"}") VAULT_TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.auth.client_token') if [ -z "$VAULT_TOKEN" ] || [ "$VAULT_TOKEN" = "null" ]; then echo "ERROR: Failed to login to Vault via JWT" echo "$LOGIN_RESPONSE" | jq . exit 1 fi echo "VAULT_TOKEN=$VAULT_TOKEN" >> "$GITHUB_ENV" - name: Read secrets from Vault KV and export to env env: VAULT_ADDRESS: ${{ secrets.VAULT_ADDRESS }} VAULT_KV_PATH: ${{ secrets.VAULT_KV_PATH }} run: | # KV v2 API endpoint: /v1//data/ # Если VAULT_KV_PATH="blog/frontend", то mount=blog, path=frontend MOUNT="${VAULT_KV_PATH%%/*}" SUBPATH="${VAULT_KV_PATH#*/}" JSON=$(curl -sS \ -H "X-Vault-Token: $VAULT_TOKEN" \ "$VAULT_ADDRESS/v1/$MOUNT/data/$SUBPATH") # Пример: вытащим 2 ключа (замени на свои) API_BASE_URL=$(echo "$JSON" | jq -r '.data.data.API_BASE_URL') if [ -z "$API_BASE_URL" ] || [ "$API_BASE_URL" = "null" ]; then echo "ERROR: API_BASE_URL is missing in Vault at $VAULT_KV_PATH" exit 1 fi # Экспортируем в env для следующих шагов: echo "API_BASE_URL=$API_BASE_URL" >> "$GITHUB_ENV" - name: Verify secrets loaded (safe) run: | # НЕ печатаем сами значения! echo "API_BASE_URL loaded: $([ -n "$API_BASE_URL" ] && echo yes || echo no)" - name: Install deps run: | corepack enable pnpm -v || true pnpm install - name: Build env: API_BASE_URL: ${{ env.API_BASE_URL }} SENTRY_DSN: ${{ env.SENTRY_DSN }} run: pnpm build