# Wild Cloud App Validation Rules # # Loaded by validate-apps.py at runtime. # Run `validate-apps.py --list-rules` for a formatted summary. # # To suppress a rule for an app, add its ID to ignoreRules in app.yaml: # ignoreRules: # - WC-HELM # upstream Helm-rendered manifests # # Fields: # severity: error (must fix before submitting) | warning (strong suggestion) # description: What the rule checks for # remediation: How to fix the issue # ── app.yaml ────────────────────────────────────────────────────────────────── WC-APP-MISS: severity: error description: app.yaml file is missing remediation: Create app.yaml with name, description, category, latest, and icon fields WC-IGN: severity: error description: app.yaml ignoreRules contains an unknown rule ID remediation: Remove the stale entry from ignoreRules, or check for a typo in the rule ID (run --list-rules to see valid IDs) WC-APP-PARSE: severity: error description: app.yaml could not be parsed as valid YAML remediation: Fix YAML syntax errors in app.yaml WC-APP-EMPTY: severity: error description: app.yaml is empty remediation: Populate app.yaml — it is empty WC-REQ: severity: error description: app.yaml missing one or more required fields remediation: "Add the missing fields: name, is, description, category, and latest are all required" WC-NAME: severity: error description: app.yaml name does not match the directory name remediation: "Set 'name:' in app.yaml to exactly match the directory name" WC-ICON: severity: warning description: app.yaml missing icon field remediation: "Add 'icon: ' to app.yaml pointing to the app's logo" # ── versions ────────────────────────────────────────────────────────────────── WC-VER: severity: error description: versions/ directory is missing remediation: Create a versions/ subdirectory with at least one version slot directory inside it WC-LATEST: severity: error description: latest version directory does not exist remediation: "Create the version slot directory named in 'latest:', or update 'latest:' to an existing slot" WC-VIA: severity: error description: upgrade.from[].via references a slot directory that does not exist remediation: "Create the waypoint slot directory, or fix the via: value to match an existing slot" WC-SLOT: severity: warning description: version slot directory name looks like a full version string or packaging revision remediation: | Rename the slot to the major version only (e.g. '1', 'v1', 'v0'). Full versions ('1.2.3') and packaging revisions ('1-2') do not belong in directory names. The actual version string lives in manifest.yaml. # ── manifest.yaml ───────────────────────────────────────────────────────────── WC-NSFILE: severity: warning description: no Namespace resource defined — workloads will deploy into an unmanaged namespace remediation: | Add a namespace.yaml listing it in kustomization.yaml resources: apiVersion: v1 kind: Namespace metadata: name: {{ .namespace }} # ── manifest.yaml ───────────────────────────────────────────────────────────── WC-MAN-MISS: severity: error description: manifest.yaml is missing remediation: "Create manifest.yaml with at minimum: version, defaultConfig.namespace" WC-MAN-PARSE: severity: error description: manifest.yaml could not be parsed remediation: Fix YAML syntax errors in manifest.yaml WC-MAN-EMPTY: severity: error description: manifest.yaml is empty remediation: Populate manifest.yaml — it is empty WC-MAN-REQ: severity: error description: manifest.yaml missing a required field remediation: "Add the missing field to manifest.yaml (at minimum: version)" WC-TVAR: severity: warning description: template variable in resource file not found in defaultConfig remediation: | Add the missing variable to defaultConfig in manifest.yaml, or check for a typo in the template. Only top-level variable names are checked — e.g. .db in {{ .db.host }} must appear as a key under defaultConfig. Global namespaces (cloud, cluster, operator, apps, secrets, app) are always available and exempt. WC-CFG: severity: warning description: manifest.yaml defaultConfig is empty or missing remediation: "Add a 'defaultConfig:' block to manifest.yaml" WC-CFG-NS: severity: warning description: manifest.yaml defaultConfig missing namespace field remediation: "Add 'namespace: ' under defaultConfig in manifest.yaml" WC-SSL: severity: error description: postgres URL missing ?sslmode=disable remediation: | Append ?sslmode=disable to the postgres connection URL: postgresql://user:pass@host:5432/db?sslmode=disable WC-DOT: severity: error description: requiredSecret does not use . dot notation remediation: "Use . format in requiredSecrets (e.g. postgres.password, not just 'password')" # ── kustomization.yaml ──────────────────────────────────────────────────────── WC-KUS-MISS: severity: error description: kustomization.yaml is missing remediation: Create kustomization.yaml listing all resource files with Wild Cloud labels WC-KUS-PARSE: severity: error description: kustomization.yaml could not be parsed remediation: Fix YAML syntax errors in kustomization.yaml WC-KUS-EMPTY: severity: error description: kustomization.yaml is empty remediation: "Add a resources: list and labels: block to kustomization.yaml" WC-RES: severity: error description: a resource listed in kustomization.yaml does not exist on disk remediation: "Create the missing file, or remove it from resources: in kustomization.yaml" WC-RES-PARSE: severity: error description: a resource file listed in kustomization.yaml could not be parsed as valid YAML remediation: Fix YAML syntax errors in the resource file WC-NS: severity: warning description: no namespace in kustomization.yaml (has Deployment/StatefulSet) remediation: "Add 'namespace: {{ .namespace }}' to kustomization.yaml" WC-SEL: severity: error description: labels.includeSelectors true missing (required for Deployment/StatefulSet) remediation: | Add to kustomization.yaml: labels: - includeSelectors: true pairs: app: managedBy: kustomize partOf: wild-cloud WC-PAIRS: severity: warning description: a standard label pair is missing or has the wrong value remediation: "Ensure labels.pairs includes managedBy: kustomize and partOf: wild-cloud" WC-LBL: severity: warning description: label pair 'app' does not match the app directory name remediation: "Set 'app:' in label pairs to match the app directory name" # ── workloads ───────────────────────────────────────────────────────────────── WC-SC-POD: severity: warning description: no pod-level securityContext defined remediation: | Add to the pod spec: securityContext: runAsNonRoot: true runAsUser: seccompProfile: type: RuntimeDefault WC-SC-CTR: severity: warning description: no container-level securityContext defined remediation: | Add to each container spec: securityContext: allowPrivilegeEscalation: false capabilities: drop: [ALL] WC-RWO: severity: error description: Deployment using a ReadWriteOnce PVC must use strategy Recreate remediation: "Set strategy: type: Recreate on the Deployment — RWO volumes cannot attach to two pods at once" WC-HELM: severity: error description: Helm-style app.kubernetes.io/* labels found in pod template remediation: "Remove app.kubernetes.io/* labels from pod template; use simple labels (e.g. component: web) instead" WC-IMG: severity: error description: container image uses a mutable or missing version tag remediation: "Pin the image to a specific release tag (e.g. myimage:1.2.3), not latest/main/stable/etc." WC-BITNAMI: severity: warning description: container image is from Bitnami — prefer an official image remediation: | Replace the Bitnami image with the official upstream image. Bitnami images require Docker Hub authentication since 2023, use non-standard filesystem layouts, and are often a sign of a Helm chart that wasn't fully adapted. Check Docker Hub or the project's docs for the official image (e.g. postgres:15, redis:alpine, mariadb:11). # ── ingress ─────────────────────────────────────────────────────────────────── WC-ING-ANN: severity: error description: ingress uses deprecated kubernetes.io/ingress.class annotation remediation: "Replace the annotation with spec.ingressClassName: traefik in the Ingress spec" WC-ING-CLS: severity: warning description: ingress spec.ingressClassName should be traefik remediation: "Add 'ingressClassName: traefik' under spec: in the Ingress" WC-CERT: severity: error description: ingress uses cert-manager annotation (wildcard cert is pre-distributed) remediation: "Remove the cert-manager.io/cluster-issuer annotation — wildcard TLS is pre-distributed to namespaces" WC-DNS: severity: warning description: ingress missing external-dns.alpha.kubernetes.io/target annotation remediation: | Add to Ingress metadata.annotations: external-dns.alpha.kubernetes.io/target: '{{ .externalDnsDomain }}' # ── db-init ─────────────────────────────────────────────────────────────────── WC-DKRDNS: severity: error description: Docker DNS resolver (127.0.0.11) used — not available in Kubernetes remediation: | Remove `resolver 127.0.0.11` and avoid nginx variables in proxy_pass. Use `proxy_pass http://backend-name:port;` (no variable) so nginx resolves via CoreDNS at startup. If a runtime-resolved variable is unavoidable, use the cluster DNS resolver instead: resolver kube-dns.kube-system.svc.cluster.local valid=30s; See docs/nginx.md for the full pattern. WC-DBIN: severity: error description: MySQL db-init uses CREATE USER without ALTER USER (passwords won't update on redeploy) remediation: | Add ALTER USER after CREATE USER so passwords update on redeploy: CREATE USER IF NOT EXISTS '${USER}'@'%' IDENTIFIED BY '${PASSWORD}'; ALTER USER '${USER}'@'%' IDENTIFIED BY '${PASSWORD}';