Add opt-in hardening to the agents-as-a-service example: - commented runtimeClassName/nodeSelector fields for sandboxes and Deployments - optional sandbox NetworkPolicy plus exposure-variant policies - optional dsh-provider-keys-extra Secret for extra provider keys - docs/optional-hardening.md with verification, caveats and rollback The base walkthrough stays portable; no gateway code, routes or auth changed. Co-authored-by: SREDevOpsAgents <agents@sredevops.org>
7.2 KiB
Example contract
Every implementation in this repository is a self-contained example under
examples/<name>/. Examples demonstrate how to run the main
DSH Web image (and, when needed, auxiliary components such as the
agents-as-a-service gateway) on Kubernetes. They are reference material, not
libraries: each one is applied with plain kubectl, documented end to end, and
deletable in one command.
examples/README.md is the index. If an example is not
listed there, it does not exist as far as make check is concerned.
Required layout
examples/<name>/
+-- README.md # required: what it demonstrates, prerequisites,
| # ordered steps, troubleshooting, cleanup
+-- manifests/ # required
| +-- NN-*.yaml # numbered top-level manifests, plain kubectl
| +-- optional/ # optional opt-in manifests, applied by path
| +-- README.md # required when optional/ exists
| +-- <feature>/NN-*.yaml # e.g. network-policy/
| +-- exposure/ # optional exposure variants
| +-- README.md # required when exposure/ exists
| +-- <variant>/NN-*.yaml # e.g. ingress/, gateway-api-sso/
+-- scripts/ # optional
| +-- *.sh # executable, idempotent, self-cleaning
+-- docs/ # optional deeper material (architecture, ADRs)
+-- <component>/ # optional published component
+-- Dockerfile
+-- README.md # required whenever a Dockerfile exists
+-- tests...
Rules the CI enforces
scripts/check-examples.sh fails the build when:
examples/README.mdis missing or does not mentionexamples/<name>/for every example directory;- an example has no
README.mdor nomanifests/directory; manifests/contains no top-level*.yamlfiles;- a
*.yamlfile sits at the example root instead of undermanifests/; manifests/exposure/exists without amanifests/exposure/README.mddescribing the variants;manifests/optional/exists without amanifests/optional/README.mddescribing the opt-in manifests;- a subdirectory with a
Dockerfilehas noREADME.md; - a file in
scripts/is not executable.
scripts/check-manifests.py additionally parses
every manifests/**/*.yaml and requires apiVersion, kind and
metadata.name. CI also runs a server-side dry-run against the real
agent-sandbox CRDs on a throwaway kind cluster.
Run both locally with:
make check
Manifests
- Numbered and ordered.
NN-*.yamlfiles are applied in filename order and read as a walkthrough:00-prereqs.yaml,10-sandboxtemplate.yaml,20-sandboxwarmpool.yaml, ... Keep the numbering stable; it is referenced from the example README. - Plain kubectl. No Helm, Kustomize, or custom installer.
kubectl apply -fagainst a namespace the example creates is the whole interface. - Safe by default. Never ship a usable Secret. Secret-shaped manifests are
*.yaml.examplefiles with obvious placeholders and an inline creation command; real values are generated per install. - Cluster-specific state stays out. Node affinity, replica counts tuned for a cluster, and similar fields belong in a local patch, not in the shipped manifest. Optional scheduler/runtime hints may ship commented out with placeholder labels; they must not be active.
- Optional manifests are opt-in. Put them under
manifests/optional/<feature>/, document them inmanifests/optional/README.md, and apply them by path. The top-levelkubectl apply -f manifests/is non-recursive and does not apply them. - Placeholders are explicit. Hostnames, GitHub orgs and TLS material use
values like
dsh.example.com/your-github-orgwith a TODO comment.
Exposure variants
An example that can be reached from outside the cluster puts each option under
manifests/exposure/<variant>/ and describes the trade-offs in
manifests/exposure/README.md. Variants are alternatives, not a stack: apply one.
dsh-agents-as-a-service currently ships:
| Variant | Path | What it gives you |
|---|---|---|
| Ingress | manifests/exposure/ingress/ |
Traefik-style Ingress + TLS; the gateway does its own session auth. |
| Gateway API + SSO | manifests/exposure/gateway-api-sso/ |
Gateway API Gateway/HTTPRoute in front of oauth2-proxy (GitHub OAuth); the gateway inherits X-Forwarded-User via AUTH_PROXY_HEADER. |
Components
A component is a program the example needs beyond the main image: today only the agents-as-a-service gateway. A component lives in its own subdirectory with:
Dockerfile— its image build;README.md— purpose, API/config reference, local development, limitations;- tests — unit tests that run without a cluster, plus whatever else applies.
Component images are published as nested packages below the repository image:
<registry>/<owner>/<repo>/<example>/<component>
so the gateway is
ghcr.io/sredevopsorg/deepseek-kubernetes-sandbox/dsh-agents-as-a-service/gateway.
Never create an unrelated top-level package; check-versions.sh verifies the
nesting.
Scripts
scripts/*.sh must be:
- executable (the CI checks the mode bit);
- idempotent — safe to re-run, cleaning up before creating;
- self-cleaning — a trap removes the namespace, port-forwards and temp files, even on failure;
- non-interactive — usable in CI, with environment-variable knobs instead of prompts.
examples/dsh-agents-as-a-service/scripts/e2e-kind.sh is the reference
implementation: it runs the README walkthrough and deletes everything it created.
Documentation
- The example
README.mdis the walkthrough. Keep it runnable: every command block should work when pasted in order. - Deeper material (architecture, sequence diagrams, ADRs) belongs in the
example's
docs/, not in the repository-level docs/. - Repository-wide docs describe the container and the repo rules; example docs describe one implementation.
Adding a new example
- Create
examples/<name>/with the layout above. - Write
README.mdfirst: what it demonstrates, prerequisites, numbered steps, troubleshooting, limitations, cleanup. - Add
manifests/NN-*.yaml; keep secrets as*.yaml.example. - If a component needs an image, publish it under
<registry>/<owner>/<repo>/<example>/<component>. - Add an entry to
examples/README.mdusing the literalexamples/<name>/path. - Run
make checkand, if you added a component,make testandmake lint. - If the example is expensive to run (kind, images, cluster CRDs), ship a
scripts/e2e-kind.shand wire it into CI.
Current examples
| Example | Demonstrates |
|---|---|
examples/dsh-agents-as-a-service/ |
The full multi-tenant platform pattern: SandboxTemplate, warm pool, per-user claims, suspend/resume, and the browser gateway. |
examples/minimal-single-tenant/ |
A single DSH Web sandbox: one SandboxTemplate and a claim. |