cloud-deploy-blueprint — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cloud-deploy-blueprint (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill captures the complete knowledge for deploying a multi-service application to cloud Kubernetes, based on battle-tested learnings from deploying TaskFlow (5 microservices) to Azure AKS.
NEXT_PUBLIC_* variables in Docker/K8s INTERNET
│
▼
┌─────────────────┐
│ Load Balancer │ (Single Public IP)
└────────┬────────┘
│
┌────────▼────────┐
│ Ingress (Traefik│ Routes by subdomain
│ or nginx) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Web │ │ SSO │ │ MCP │
│ (PUBLIC) │ │ (PUBLIC) │ │ (PUBLIC) │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ ┌────▼─────┐ │
└──────────────► API ◄─────────────┘
│(INTERNAL)│
└────┬─────┘
│
┌────────────┴────────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Neon │ │ Upstash │
│ (Postgres) │ │ (Redis) │
│ EXTERNAL │ │ EXTERNAL │
└─────────────┘ └─────────────┘Next.js NEXT_PUBLIC_* variables are embedded at build time, not runtime. This means:
# WRONG: Setting NEXT_PUBLIC_* at runtime does NOTHING
ENV NEXT_PUBLIC_API_URL=https://api.example.com
# RIGHT: Must be set as build ARG
ARG NEXT_PUBLIC_API_URL=https://api.example.com
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL| Service | Variable | Purpose |
|---|---|---|
| Web | NEXT_PUBLIC_SSO_URL | SSO endpoint for browser OAuth |
| Web | NEXT_PUBLIC_API_URL | API endpoint for browser fetch |
| Web | NEXT_PUBLIC_APP_URL | App URL for redirects |
| SSO | NEXT_PUBLIC_BETTER_AUTH_URL | Better Auth URL for browser |
| SSO | NEXT_PUBLIC_CONTINUE_URL | Redirect after email verify |
| Service | Variable | Source |
|---|---|---|
| SSO | DATABASE_URL | Secret (Neon) |
| SSO | BETTER_AUTH_SECRET | Secret |
| API | SSO_URL | ConfigMap (internal K8s URL) |
| MCP | TASKFLOW_SSO_URL | ConfigMap (internal K8s URL) |
Services communicate via K8s service names, NOT public URLs:
# CORRECT - Internal communication
SSO_URL: http://sso-platform:3001
API_URL: http://taskflow-api:8000
# WRONG - Don't use public URLs for internal traffic
SSO_URL: https://sso.example.comjobs:
changes:
runs-on: ubuntu-latest
outputs:
api: ${{ steps.filter.outputs.api }}
web: ${{ steps.filter.outputs.web }}
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
api:
- 'apps/api/**'
web:
- 'apps/web/**'
build-api:
needs: changes
if: needs.changes.outputs.api == 'true' || github.event_name == 'workflow_dispatch'- name: Build and push (web)
uses: docker/build-push-action@v5
with:
build-args: |
NEXT_PUBLIC_SSO_URL=https://sso.${{ vars.DOMAIN }}
NEXT_PUBLIC_API_URL=https://api.${{ vars.DOMAIN }}
NEXT_PUBLIC_APP_URL=https://${{ vars.DOMAIN }}NEON_SSO_DATABASE_URL
NEON_API_DATABASE_URL
NEON_CHATKIT_DATABASE_URL
NEON_NOTIFICATION_DATABASE_URL
UPSTASH_REDIS_HOST
UPSTASH_REDIS_PASSWORD
REDIS_URL
REDIS_TOKEN
BETTER_AUTH_SECRET
OPENAI_API_KEY
SMTP_USER
SMTP_PASSWORD
AZURE_CREDENTIALS (or GCP_CREDENTIALS)DOMAIN=example.com
CLOUD_PROVIDER=azure
AZURE_RESOURCE_GROUP=myapp-rg
AZURE_CLUSTER_NAME=myapp-cluster
INGRESS_CLASS=traefikglobal:
domain: "" # Set via --set
namespace: taskflow
imagePullPolicy: Always
managedServices:
neon:
enabled: true
# Connection strings injected via --set from secrets
upstash:
enabled: true
# Credentials injected via --set from secrets
sso:
enabled: true
name: sso-platform
postgresql:
enabled: false # Using Neon
env:
NODE_ENV: production
BETTER_AUTH_URL: "" # Set via --sethelm upgrade --install taskflow ./infrastructure/helm/taskflow \
--values values-cloud.yaml \
--set global.imageRegistry="ghcr.io/owner/repo" \
--set global.imageTag="${{ github.sha }}" \
--set "managedServices.neon.ssoDatabase=${{ secrets.NEON_SSO_DATABASE_URL }}" \
--set "sso.env.BETTER_AUTH_SECRET=${{ secrets.BETTER_AUTH_SECRET }}"BEFORE ANY DEPLOYMENT, check your cluster's node architecture:
kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.architecture}'amd64 → Use platforms: linux/amd64arm64 → Use platforms: linux/arm64ARM64 is increasingly common (Azure, AWS Graviton, Apple Silicon dev). Don't assume amd64!
- uses: docker/build-push-action@v5
with:
platforms: linux/arm64 # MATCH YOUR CLUSTER!
provenance: false # Avoid manifest issues
no-cache: true # When debuggingWhy `provenance: false`? Buildx attestation creates complex manifest lists that can cause "no match for platform" errors. Disable for simple, reliable images.
Problem: request.url in K8s returns container bind address Solution: Use NEXT_PUBLIC_APP_URL env var for redirects
// WRONG
const response = NextResponse.redirect(new URL("/", request.url));
// RIGHT
const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
const response = NextResponse.redirect(new URL("/", APP_URL));Problem: Missing NEXT_PUBLIC_CONTINUE_URL in SSO Dockerfile Solution: Add to Dockerfile and CD pipeline:
ARG NEXT_PUBLIC_CONTINUE_URL=http://localhost:3000
ENV NEXT_PUBLIC_CONTINUE_URL=$NEXT_PUBLIC_CONTINUE_URLProblem: NEXT_PUBLIC_* not passed as build arg Solution: Check ALL NEXT_PUBLIC_* variables systematically:
grep -r "NEXT_PUBLIC_" apps/web/src --include="*.ts" --include="*.tsx" | \
grep -oE "NEXT_PUBLIC_[A-Z_]+" | sort -uProblem: Email/passwords hardcoded in values files Solution: Use --set from GitHub Secrets for ALL sensitive data
Problem: Helm templates expect database.host, postgresql.name etc. Solution: Include empty/default sections even for managed services:
postgresql:
enabled: false
name: sso-platform-postgres
database:
host: ""
port: "5432"
name: taskflow_sso
user: postgresapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: traefikannotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.tls: "true"NEXT_PUBLIC_* vars documented and in Dockerfilesrequest.urlNEXT_PUBLIC_* as ARG and ENVaks-deployment-troubleshooter - Debug ImagePullBackOff, CrashLoopBackOff, architecture issuescontainerize-apps - Dockerization patternshelm-charts - Helm chart structurekubernetes-essentials - K8s fundamentalsbetter-auth-sso - SSO integrationimpact-analyzer-agent - Pre-containerization analysis~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.