Skip to main content

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

  1. 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 K8s Secret.
  2. On first ssg invocation inside the pod, the CLI sees SSG_API_KEY=ssg_pat_… and POSTs it to accounts.sigmashake.com/api/v1/auth/cli/exchange-token.
  3. The server returns a signed license JWT bound to your current tier: 30 days for Pro, 90 days for Enterprise.
  4. The CLI caches the JWT at /root/.sigmashake/license.jwt (mode 0600) 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 -), then kubectl 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 the license-cache PVC and recreate the deployment.
  • Blast radius: a CLI token authorizes ssg against your account tier only. It cannot sign in to the web dashboard, create new tokens, or modify billing.

Troubleshooting

SymptomLikely causeFix
Pod logs show API key exchange failed: HTTP 402Free-tier tokenExpected — upgrade to Pro to receive a JWT, or drop SSG_API_KEY to use the free tier
Pod logs show HTTP 401Token revoked or malformedMint a new token, rotate the Secret
Repeated exchange calls on every pod startNo persistent cacheMount a PVC at /root/.sigmashake
license.jwt missing after restartemptyDir volume instead of PVCSwitch to PersistentVolumeClaim

Set SSG_DEBUG=1 in the pod env to surface exchange failures to stderr.


See also