Validation: ci adapter-node validate smoke check (#12)

validation-12-2026-04-30 Doc

validation partial

Verdict: PARTIAL

Ticket

forgejo_admin/westside-admin#12PR #13 (squash-merged 2026-04-30 12:26:39 UTC, merge SHA 803e9439). Replaced test -f build/index.html with test -f build/index.js + test -f build/handler.js in the .woodpecker.yaml validate step so it asserts on artifacts @sveltejs/adapter-node actually produces.

Environment

  • Cluster: archbox k3s, namespace westside-admin
  • Funnel: https://westside-admin.tail5b443a.ts.net
  • Image: harbor.tail5b443a.ts.net/westside-admin/app:803e9439806cb644cc824fa8fbd87cc5d0f567e2
  • ArgoCD app: westside-admin (auto-sync) — reconciled at 2026-04-30T12:30:05Z
  • Pipeline: forgejo_admin/westside-admin#3 (event=push, branch=main, all 4 steps success)

Checks

# Criterion How Verified Result Evidence
1 AC1: <code>.woodpecker.yaml</code> validate asserts on adapter-node artifacts (<code>build/index.js</code>, <code>build/handler.js</code>) Pipeline #3 + #2 logs grep validate step output PASS Pipeline #3 validate logs end with <code>+ test -f build/index.js</code> then <code>+ test -f build/handler.js</code> exit 0. Pipeline #2 (PR) shows the same.
2 AC2: a fresh pipeline against main reaches build-and-push Woodpecker MCP <code>get_pipeline_status</code> for #3 PASS Pipeline #3 (event=push) all 4 steps success: clone, validate, build-and-push, update-kustomize-tag.
3 AC3: no regression in <code>pull_request</code> runs (validate still gates Kaniko) Pipeline #2 (event=pull_request) status PASS Pipeline #2 ran 2 steps (clone, validate) then stopped — Kaniko correctly skipped on PR per <code>when: branch: main</code>. Validate gate intact.
4 Image exists in Harbor under merge commit SHA Harbor API <code>/projects/westside-admin/repositories/app/artifacts</code> PASS Tag <code>803e9439806cb644cc824fa8fbd87cc5d0f567e2</code>, digest <code>sha256:d350d5c5c05fea</code>, pushed 2026-04-30T12:27:11Z (28 sec after merge).
5 pal-e-deployments has auto-commit bumping <code>overlays/westside-admin/prod</code> newTag Forgejo commits API for <code>overlays/westside-admin</code> path PASS Commit <code>576eacacde</code>: <code>[skip ci] westside-admin: update image tag to 803e9439806cb644cc824fa8fbd87cc5d0f567e2</code>. Replaced the 40-zeros placeholder. Visible in <code>kustomization.yaml</code> <code>newTag</code>.
6 ArgoCD app <code>westside-admin</code> Synced + Healthy <code>kubectl get application -n argocd westside-admin -o jsonpath</code> PARTIAL Sync status: <code>Synced</code> at revision <code>576eacac</code>. Health status: <code>Progressing</code> (waiting on rollout). Operation phase: <code>Succeeded</code>. ArgoCD did its job; pod creation is what's failing downstream.
7 Deployment <code>westside-admin</code> 1/1 ready <code>kubectl get deploy -n westside-admin</code> FAIL 0/1 ready, 2 unavailable replicas. Deployment image is correct (<code>...:803e9439...</code>) but pods cannot be created.
8 Pod boots cleanly; logs show no startup errors <code>kubectl get pods -n westside-admin</code> and events FAIL Zero pods exist. Three replicasets (<code>566d4cc96d</code>, <code>6fb5db9c6</code>, <code>bcb595854</code>) all show 0/1 created. Events: <code>FailedCreate</code> — <code>pods "..." is forbidden: violates PodSecurity "restricted:latest"</code> (allowPrivilegeEscalation, capabilities.drop, runAsNonRoot, seccompProfile not set).
9 <code>/health</code> endpoint returns 200 <code>curl -s -o /dev/null -w "%{http_code}" https://westside-admin.tail5b443a.ts.net/health</code> FAIL Returns <code>000</code> (connection drops). Root URL returns <code>502</code> from the Tailscale funnel because no backend pod exists to serve traffic.

Regression Check

The PR itself introduces no regression. Pipeline #2 (PR event) ran clean — validate now passes against adapter-node artifacts and Kaniko correctly skips on PR per the existing when: branch: main gate. Pipeline #3 (push event) reached every step. The downstream pod failure is not caused by PR #13: it is a pre-existing namespace configuration gap that was previously masked by the placeholder image tag (0000...0000) keeping the deployment in ImagePullBackOff rather than reaching the PSA admission controller.

Discovered Issues

Pod creation blocked by PodSecurity admission "restricted:latest". The westside-admin namespace is labeled pod-security.kubernetes.io/enforce: restricted + enforce-version: latest in overlays/westside-admin/prod/namespace.yaml, but neither the base manifest at bases/standard/deployment.yaml nor the overlay's deployment-patch.yaml sets the four fields PSA-restricted requires:
  • spec.template.spec.containers[].securityContext.allowPrivilegeEscalation: false
  • spec.template.spec.containers[].securityContext.capabilities.drop: ["ALL"]
  • spec.template.spec.containers[].securityContext.runAsNonRoot: true
  • spec.template.spec.containers[].securityContext.seccompProfile.type: RuntimeDefault
Sister namespace westside-streamlit has the identical PSA enforcement and is also at 0 pods (its deployment was also never running). Other prod namespaces (basketball-api, westsidekingsandqueens, pal-e-app, pal-e-docs) have no PSA label and so are unaffected. Two coupled gaps: (a) the PSA label in the overlay was added without coordinating securityContext on the workload; (b) the base manifest bases/standard/deployment.yaml doesn't set securityContext, so any overlay that adopts PSA-restricted will hit this. Recommend a follow-up Forgejo issue against pal-e-deployments to either add securityContext to bases/standard/deployment.yaml (preferred — benefits every consumer) or patch it in the overlays/westside-admin/prod overlay specifically. The same fix unblocks westside-streamlit.

Summary

The merge of PR #13 successfully fixed the bug it set out to fix — all three acceptance criteria from issue #12 are met, and the deploy chain (build → push → tag bump → ArgoCD sync) now works end-to-end for the first time in westside-admin's history. The image is in Harbor under the correct SHA; pal-e-deployments has the auto-commit; ArgoCD has applied the new manifest. However, the broader bootstrap goal — westside-admin actually serving traffic — is blocked by a separate PSA-restricted namespace policy that no workload manifest in the deploy chain satisfies. This is an infrastructure gap, not a regression. Verdict PARTIAL: ticket-level ACs all PASS; production readiness PARTIAL pending the PSA fix.