Kubernetes
ssg runs in any Kubernetes pod that can pull ghcr.io/sigmashakeinc/ssg:latest. The only wrinkle is authentication: browser-based ssg auth login can't open a browser inside a container. For Pro / Enterprise tiers, use a personal access token bound to the SSG_API_KEY environment variable — the CLI exchanges it for a signed license JWT on first run and caches the JWT to disk.
Free-tier pods don't need any credential at all (5,000 evals/day still applies).
How headless auth works
- You create a CLI token at
accounts.sigmashake.com/settings/tokens. The page shows the full token once (format:ssg_pat_<32-hex>) — store it in a password manager or drop it straight into a K8sSecret. - On first
ssginvocation inside the pod, the CLI seesSSG_API_KEY=ssg_pat_…andPOSTs it toaccounts.sigmashake.com/api/v1/auth/cli/exchange-token. - The server returns a signed license JWT bound to your current tier: 30 days for Pro, 90 days for Enterprise.
- The CLI caches the JWT at
/root/.sigmashake/license.jwt(mode0600) and reuses it until 24 hours before expiry, at which point it proactively re-exchanges.
If you mount a PersistentVolumeClaim (or even an emptyDir) at /root/.sigmashake, the JWT survives across pod restarts — no repeated exchange traffic.
Step 1 — Create the API key Secret
kubectl create secret generic ssg-api-key \
--from-literal=SSG_API_KEY=ssg_pat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
--namespace=ai-governance
Or declaratively (base64-encoded value):
apiVersion: v1
kind: Secret
metadata:
name: ssg-api-key
namespace: ai-governance
type: Opaque
stringData:
SSG_API_KEY: ssg_pat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Step 2 — Deployment with PVC-backed JWT cache
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ssg-license
namespace: ai-governance
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 16Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ssg-dashboard
namespace: ai-governance
spec:
replicas: 1
selector:
matchLabels:
app: ssg-dashboard
template:
metadata:
labels:
app: ssg-dashboard
spec:
containers:
- name: ssg
image: ghcr.io/sigmashakeinc/ssg:latest
args: ["serve", "--port", "5599"]
ports:
- containerPort: 5599
env:
- name: SSG_API_KEY
valueFrom:
secretKeyRef:
name: ssg-api-key
key: SSG_API_KEY
volumeMounts:
- name: license-cache
mountPath: /root/.sigmashake
- name: rules
mountPath: /work/.sigmashake
workingDir: /work
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: license-cache
persistentVolumeClaim:
claimName: ssg-license
- name: rules
configMap:
name: ssg-rules
---
apiVersion: v1
kind: Service
metadata:
name: ssg-dashboard
namespace: ai-governance
spec:
selector:
app: ssg-dashboard
ports:
- port: 5599
targetPort: 5599
The license-cache volume holds the exchanged JWT; the rules volume holds your .rules files (shown here as a ConfigMap, but a git-sync sidecar or PVC works too).
Step 3 — Run one-shot evals as a Job
For CI-style policy gates that terminate after a single evaluation:
apiVersion: batch/v1
kind: Job
metadata:
name: ssg-eval
namespace: ai-governance
spec:
template:
spec:
restartPolicy: Never
containers:
- name: ssg
image: ghcr.io/sigmashakeinc/ssg:latest
command: ["sh", "-c"]
args:
- echo '{"tool":"Bash","input":{"command":"rm -rf /"}}' | ssg eval
env:
- name: SSG_API_KEY
valueFrom:
secretKeyRef:
name: ssg-api-key
key: SSG_API_KEY
Jobs run briefly, so the JWT cache isn't worth a PVC — the exchange adds ~200ms on first call and short-circuits on subsequent calls within the same pod.
Free tier — no auth needed
If you're on the free tier, skip the Secret entirely. The CLI runs offline with the built-in 5,000-evals/day quota:
containers:
- name: ssg
image: ghcr.io/sigmashakeinc/ssg:latest
args: ["eval"]
# No env vars, no volumes — just works.
The exchange endpoint returns HTTP 402 for free-tier tokens, so don't bother minting one; the CLI handles the missing JWT gracefully and falls through to free-tier evaluation.
Token rotation and revocation
- Rotation: mint a new token, update the Secret (
kubectl create secret … --dry-run=client -o yaml | kubectl apply -f -), thenkubectl rollout restart deployment/ssg-dashboard. The new pod writes a fresh JWT on startup. - Revocation: revoke at
accounts.sigmashake.com/settings/tokens. Future exchanges fail immediately. Already-cached JWTs keep working until they expire (up to 30 / 90 days) — if faster cutoff matters, delete thelicense-cachePVC and recreate the deployment. - Blast radius: a CLI token authorizes
ssgagainst your account tier only. It cannot sign in to the web dashboard, create new tokens, or modify billing.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Pod logs show API key exchange failed: HTTP 402 | Free-tier token | Expected — upgrade to Pro to receive a JWT, or drop SSG_API_KEY to use the free tier |
Pod logs show HTTP 401 | Token revoked or malformed | Mint a new token, rotate the Secret |
| Repeated exchange calls on every pod start | No persistent cache | Mount a PVC at /root/.sigmashake |
license.jwt missing after restart | emptyDir volume instead of PVC | Switch to PersistentVolumeClaim |
Set SSG_DEBUG=1 in the pod env to surface exchange failures to stderr.
See also
- CLI Reference —
ssg authfor all auth modes - Docker image reference — tags, registry, and build instructions
- Getting Started — quick install for local development