Create staging builds to validate Flux deploys #54

Merged
tepichord merged 12 commits from feat/49-staging-builds into main 2026-09-11 19:40:55 -07:00
Owner

Closes #49

Automated PR created by forgejo-done adapter.

Closes #49 Automated PR created by forgejo-done adapter.
Makes the L1 policy gate (policy/k8s.rego) runnable locally, so a rule
change can be checked without a pipeline round-trip.

Refs: #49
Sets WOODPECKER_BACKEND_K8S_SERVICE_ACCOUNT_NAME_ALLOW_FROM_STEP so the
L2/L3 gates can run as preview-deployer instead of shipping a cluster
credential into a repo secret.

Refs: #49
CI creates intent (Namespace, values ConfigMap, GitRepository,
Kustomization) and Flux applies workloads, so preview-deployer gets
namespaces get/list/create/delete cluster-wide and CRUD on those three
kinds in preview-system only. The reaper is the teardown path that does
not depend on a PR-close webhook arriving from the off-tailnet forge.

Refs: #49
apps/base is environment-agnostic: no namespace, and each env variant is a
placeholder. apps/prod fills them from cluster-config-prod; apps/preview
pins the PVC to the ephemeral tier, deletes the Tailscale Ingress, caps
replicas at 1, and applies a ResourceQuota/LimitRange.

Refs: #49
Three rules — no moving image tags, CPU and memory limits required, no
privileged containers. Deliberately small: a policy framework is bypassed
within a month at this scale.

Refs: #49
VSO 1.5's field has no omitempty, so the generated CRD marks it required.
The new CRD-catalog schema check in L1 rejects the manifest without it.

Refs: #49
L0 renders every Flux layer (including preview-system) and both app
overlays offline; L1 runs kubeconform with the CRD catalog plus the
conftest policy; L2 diffs the preview overlay against the API server as
preview-deployer; L3 creates a preview namespace and waits for Flux to
reach Kustomization Ready. The CRD-catalog schema location is what stops
L1 silently skipping every Flux/KEDA/VSO custom resource.

Refs: #49
Adds static guards for the ephemeral storage patch, the Tailscale Ingress
deletion, preview-namespace PSA labels, the reaper annotation and its
three deletes, preview-deployer's RBAC scope, and the four pipeline
gates. Also renders both overlays (when kustomize is available) and
exercises policy/k8s.rego's four failure modes with conftest.

Refs: #49
Refs: #49
The untagged-image rule used `not contains(image, ":")`, so a registry
with a port (`registry.local:5000/nginx`) read as tagged and an untagged
image passed L1. Check the last path segment for the tag instead, and keep
`@` as the digest form. Add a regression test for both the port-only and
port-plus-tag cases.
fix(ci): reap the preview values ConfigMap and drop the unreachable log dump
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
6aca657dab
The L3 step creates `preview-<n>-values` in preview-system, where no
preview-namespace delete reaches it, and it carried no expiry annotation
and no reaper grant — one leaked ConfigMap per pull request forever. Stamp
it with `milner.dev/preview-expires` like the other preview objects and
let the reaper's existing annotation sweep collect it (Role gains
configmaps).

Also correct the L3 failure path: it read events, Deployment and pod logs
from preview-<n>, but preview-deployer is only bound in preview-system, so
every one of those calls was Forbidden behind `|| true`. The workloads
move with the Kustomization's targetNamespace, and a per-preview binding is
not something CI can create without widening its RBAC for logs alone, so
the dump now reports the Kustomization status (which carries the
health-check failure) and the unused pods/events grant is removed.
tepichord added this to the MVP project 2026-09-11 18:49:01 -07:00
fix(preview-system): preserve deployer namespace and grant watch verb
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
37d719ed61
tepichord deleted branch feat/49-staging-builds 2026-09-11 19:40:55 -07:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
tepichord/milner!54
No description provided.