expose-zymtrace-backend — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited expose-zymtrace-backend (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
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.
Helps the user expose the gateway service externally. The zymtrace gateway is the single external surface — UI, ingest (gRPC), and symdb (HTTP) all flow through it.
Deep details (LoadBalancer one-liner, ACM cert lookup, cert-manager) live in ${CLAUDE_PLUGIN_ROOT}/skills/expose-zymtrace-backend/reference.md.
Backend must already be installed (helm list -A | grep -i zymtraceshows a release). If not, useinstall-zymtrace-backend.
values.yaml (ingress + gateway service keys): <https://raw.githubusercontent.com/zystem-io/zymtrace-charts/main/charts/backend/values.yaml>##### Claude runs
helm version --short && kubectl version --client
kubectl cluster-info | head -2
helm list -A | grep -i zymtrace
kubectl get ingressclassIf helm/kubectl are missing → point to install docs; do not install them. If no zymtrace release exists → wrong skill, route to install-zymtrace-backend.
Resolve namespace + release name first. Recommended defaultszymtrace/backend; for an existing release use its namespace and name. Full policy:shared/conventions.md. Commands use<NS>and<REL>as placeholders.
| Variable | Resolve by | |
|---|---|---|
| Existing release | `helm list -A \ | grep -i zymtrace` (one match → use it; multiple → ask) |
| Current values (so we layer onto them) | helm get values <REL> -n <NS> > current-values.yaml | |
| Available ingress controllers | kubectl get ingressclass (alb / nginx / traefik) | |
| AWS LBC installed? | kubectl get deploy -n kube-system aws-load-balancer-controller | |
| Cloud / region (for ACM cert lookup) | kubectl config current-context → ARN parts; or aws configure get region | |
| Existing ingress in this NS | kubectl get ingress -n <NS> |
Things you must ask:
Pick the row that fits, then go to Standard flow below.
| Mode | Template / how | When |
|---|---|---|
| ClusterIP (default) | Already done. kubectl port-forward -n <NS> svc/<PREFIX>-gateway 8080:80 | Dev / verify only. No external exposure. |
| NodePort | values/nodeport.yaml | PoC, on-prem clusters with no cloud LB. No TLS. |
| LoadBalancer (cloud LB) | --set services.gateway.service.type=LoadBalancer (no dedicated template) — see reference.md § LoadBalancer one-liner | Rare. Most prod paths use Ingress instead because of cost + routing flexibility. |
| Ingress: NGINX + TLS | values/ingress-nginx.yaml | On-prem / non-AWS k8s with NGINX controller. cert-manager TLS. |
| Ingress: AWS ALB + TLS | values/ingress-alb.yaml | EKS. HTTPS via ACM (required). Internal or internet-facing via annotation toggle. |
ALB is HTTPS-only. Never propose HTTP-only ALB exposure, including internal-scheme ALBs. The template always requires an ACM cert ARN.
gRPC backend-protocol depends on the controller. NGINX/Traefik →backend-protocol: "GRPC". ALB →backend-protocol: HTTP+backend-protocol-version: HTTP2(the 464 trap).
First ask: does the customer already have a values file for this release?
acme-zymtrace.yaml, backend-values.yaml). Don't rename — their CI scripts and git history reference that name.zymtrace-custom-values.yaml from the live release. From then on it's canonical.##### Claude runs (only if the customer doesn't have a file)
helm get values <REL> -n <NS> > zymtrace-custom-values.yaml
cat zymtrace-custom-values.yamlSee shared/conventions.md for the full rule. Use <values-file> below as a placeholder for whichever filename you settled on.
Before any edit, take a timestamped backup so the customer can revert if anything goes wrong:
##### Claude runs
cp <values-file> <values-file>.bak.$(date +%Y%m%d-%H%M%S)Tell the user the backup path. See shared/conventions.md § Always back up before writing.
Then use the matching template in values/ as a reference snippet — not a separate file. Read it, then edit the customer's canonical file directly to add or replace the ingress: block (and services.gateway.service: if NodePort).
Things to customize while editing:
ingress.hosts.gateway.host).alb.ingress.kubernetes.io/certificate-arn) for ALB.letsencrypt-prod).internal ↔ internet-facing).Show the diff to the user and get confirmation before saving. If the customer has comments / ordering in their file, preserve them — targeted insert/replace, not a wholesale rewrite.
If the canonical file already has an ingress: block, replace it (don't append a duplicate key).
##### Claude runs
helm repo update zymtraceMandatory before any helm upgrade — see shared/conventions.md.
Print the exact command + the resolved values (release name, namespace, canonical values-file path, target hostname, TLS source). Wait for explicit confirmation. Do not run on assumed consent.
##### Claude runs
helm upgrade --install <REL> zymtrace/backend \
--namespace <NS> \
-f <values-file> \
--reset-then-reuse-values \
--atomic --debugSingle -f — the canonical file already contains the new ingress block from Step 2. --atomic rolls back the helm release on failure; the file edit from Step 2 stays on disk (git lets the user revert it if needed).
ERROR: failed pre-install: timed out waiting for the condition — usually means the ALB / NGINX LB isn't provisioning. Check:
kubectl logs -n kube-system deploy/aws-load-balancer-controller --tail=50.kubectl describe ingress -n <NS>.kubernetes.io/role/internal-elb=1 (internal) or kubernetes.io/role/elb=1 (internet-facing).ERROR: ALB returns HTTP 464 to your curl — you set backend-protocol: GRPC instead of backend-protocol: HTTP + backend-protocol-version: HTTP2. Fix and re-apply.
ERROR: TLS cert mismatch (ssl_error_bad_cert_domain in browser) — ACM cert CN/SAN doesn't include the hostname you set under hosts.gateway.host. Issue a new ACM cert or use a hostname that matches.
##### Claude runs
bash ${CLAUDE_PLUGIN_ROOT}/skills/expose-zymtrace-backend/scripts/verify-exposure.sh <NS> <REL>Checks: ingress address resolves, TLS handshake succeeds (if TLS), gateway HTTP probe returns a non-5xx response, agent gRPC port is reachable.
The canonical <values-file> already reflects the deployed state (Step 2 edited it, Step 5 applied it, Step 6 verified it). Recommend the user commit:
git add <values-file>
git commit -m "zymtrace: add <controller> exposure for <NS>/<REL>"No helm get values refresh needed — the file you edited is the source of truth.
Exit when ALL of the following are true (substitute <NS> / <REL> / <PREFIX>):
helm status <REL> -n <NS> reports STATUS: deployed and REVISION incremented.kubectl get ingress -n <NS> shows a populated ADDRESS column (FQDN or IP — may take 1–3 min for cloud LBs).kubectl get svc -n <NS> <PREFIX>-gateway shows NodePort and a port in 30000-32767.curl -fsI https://<host> returns 2xx/3xx/4xx (not connection-refused / cert error / 5xx).dig +short <host> returns the LB address.grpcurl -insecure <host>:443 list (or equivalent) reaches the gateway's gRPC listener. (Optional but recommended before pointing agents at the new exposure.)HTTP + backend-protocol-version: HTTP2. See reference.md.kubernetes.io/role/internal-elb=1 on private subnets; external needs kubernetes.io/role/elb=1 on public subnets. Missing tags = LB never provisions.helm upgrade / helm upgrade --install for this chart without --reset-then-reuse-values. See shared/conventions.md.-f <values-file>.helm repo update against the wrong repo or skip it before the upgrade. Stale cache → wrong chart version pulled.ADDRESS column is not exposed.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.