Team alpha's conformance product — scaffolded by the platform's New Product template
(ADR-067 v3), language go. A minimal containerized HTTP service (web)
plus the policy-compliant Kubernetes manifests and the thin CI that builds, signs, and ships it.
| Path | Purpose |
|---|---|
| the app source + its build manifest | Minimal go HTTP service: GET /healthz (probe) + GET / (JSON) on :8080, graceful SIGTERM shutdown. No cloud deps. |
Dockerfile |
Multi-stage, non-root, multi-arch build → minimal (distroless where available) final image. The language-specific surface. |
k8s/base/ + k8s/overlays/<stage>/ |
Namespace-/host-agnostic base/ + thin per-stage overlays (dev/test/uat/staging/prod). The per-Product ApplicationSet syncs k8s/overlays/<stage>, injecting the namespace + host; deploy.yml pins the dev overlay's image digest (promotion to other stages is by PR). Resources/probes are sized for go. |
.github/workflows/ |
deploy.yml/preview.yml (thin callers of asanexample/trusted-ci), validate.yml (overlay/ns guards + unit test), security.yml (Trivy + Semgrep). dependabot.yml keeps deps + base images current. |
deploy.yml is a few small jobs that call shared, app-team-unwritable reusable workflows:
- build →
trusted-ci/build-sign.yml— builds the image, pushes it to the product-scoped repoteam-alpha/conformance-webin the platform ECR (via the per-Product OIDC rolegithub-actions-ecr-push-product-alpha-conformance), cosign-keyless-signs it, attaches a CycloneDX SBOM. - provenance →
trusted-ci/slsa-provenance.yml— attaches the SLSA build provenance (SLSA Build L3). - deploy — pins the freshly signed digest into
k8s/overlays/dev/kustomization.yamland commits it; the per-Product ApplicationSet syncs it. Promotion to test/uat/staging/prod is by PR (promote-by-PR).
Signatures, SBOM, and provenance carry this repo's identity (the githubWorkflowRepository cert extension),
which the platform's Kyverno verify-images-product / verify-attestations-product policies require at
admission. Nothing per-app to maintain — it lives in trusted-ci.
- Do not hardcode a hostname or namespace — the platform injects both (the ApplicationSet sets the
destination namespace and patches the real host onto the
HTTPRoute). Leave theplaceholder.invalidhost and the namespace-agnosticbase/. - Replace
cmd//Dockerfilewith your real app — keep/healthzon:8080, or update the probes/port inbase/deployment.yaml. - A new Service for this product → add
k8s/base/<service>.yaml+ its image; a new Stage/Environment → use the New Environment portal template (authorsgitops/environments/alpha/conformance/<stage>.yaml).
The team and product were registered in the platform repo — the gitops/products/alpha/conformance.yaml
registry entry and the dev Environment claim — by the same New Product run. See docs/runbooks/app-supply-chain-onboarding.md.
Need an S3 bucket (more engines coming)? Declare it on the Service in your Environment claim
(gitops/environments/alpha/conformance/<stage>.yaml) — no Crossplane/AWS to write:
spec:
services:
web:
serviceAccount: app-alpha
resources:
uploads: { kind: objectstore, engine: s3, access: readwrite } # access: read | readwriteThe platform provisions the bucket safe-by-construction (encrypted, private, versioned, TLS-only), derives
least-privilege IAM scoped to that bucket only onto the Service's Pod-Identity role, and publishes the
name into a web-resources ConfigMap. base/deployment.yaml already envFroms it
(optional: true), so UPLOADS_BUCKET appears as an env var after the next rollout. Your Team must allow the
engine in its envelope (platform-team-owned); the gate validates the request on the PR.