98 lines
5.9 KiB
Python
Executable File
98 lines
5.9 KiB
Python
Executable File
"""Offline invariants for manifests rendered by real Ansible/Jinja."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
from kubernetes_validate import validate
|
|
|
|
|
|
def docs(name):
|
|
return [doc for doc in yaml.safe_load_all(Path(f"/tmp/www-test-{name}.yml").read_text()) if doc]
|
|
|
|
|
|
def find(objects, kind, name):
|
|
return next(obj for obj in objects if obj["kind"] == kind and obj["metadata"]["name"] == name)
|
|
|
|
|
|
def pod_checks(pod, external=False):
|
|
assert pod["automountServiceAccountToken"] is False
|
|
assert pod["securityContext"]["runAsNonRoot"] is True
|
|
container = pod["containers"][0]
|
|
assert container["securityContext"]["readOnlyRootFilesystem"] is True
|
|
assert container["securityContext"]["capabilities"]["drop"] == ["ALL"]
|
|
assert container["envFrom"] == [{"configMapRef": {"name": "membership-config"}}, {"secretRef": {"name": "membership"}}]
|
|
assert not container.get("env")
|
|
assert container["resources"]["limits"]["memory"]
|
|
assert any(mount["mountPath"] == "/etc/membership/tiers" and mount["readOnly"] for mount in container["volumeMounts"])
|
|
if external:
|
|
assert pod["imagePullSecrets"] == [{"name": "registry-pull"}]
|
|
assert any(volume.get("secret", {}).get("secretName") == "private-ca" for volume in pod["volumes"])
|
|
assert any(mount["mountPath"] == "/etc/membership/ca" and mount["readOnly"] for mount in container["volumeMounts"])
|
|
|
|
|
|
all_objects = []
|
|
for name in ["website", "membership-config", "membership-postgres", "membership-migrate", "membership-workloads"]:
|
|
all_objects.extend(docs(name))
|
|
for path in Path('/tmp').glob('www-test-*.yml'):
|
|
for obj in yaml.safe_load_all(path.read_text()):
|
|
if obj and obj['kind'] != 'OnionService':
|
|
validate(obj, desired_version='1.31.0', strict=True)
|
|
assert all(obj["metadata"]["namespace"] == "www" for obj in all_objects)
|
|
assert len({(obj["kind"], obj["metadata"]["name"]) for obj in all_objects}) == len(all_objects)
|
|
config = find(all_objects, "ConfigMap", "membership-config")["data"]
|
|
assert all(isinstance(value, str) for value in config.values())
|
|
assert config["MEMBERSHIP_PUBLIC_URL"] == "https://www.eom.dev"
|
|
assert config["LDAP_ALLOW_INSECURE"] == "0"
|
|
assert config["LDAP_URL"].startswith("ldaps://")
|
|
plaintext_config = find(docs("plaintext-membership-config"), "ConfigMap", "membership-config")["data"]
|
|
assert plaintext_config["LDAP_ALLOW_INSECURE"] == "1"
|
|
assert plaintext_config["LDAP_URL"] == "ldap://openldap.openldap.svc.cluster.local:389"
|
|
assert all(isinstance(value, str) for value in plaintext_config.values())
|
|
assert "MEMBERSHIP_SECRET_KEY" not in config and "SHKEEPER_API_KEY" not in config
|
|
tiers = json.loads(find(all_objects, "ConfigMap", "membership-tiers")["data"]["tiers.json"])
|
|
assert len(tiers) == 5 and tiers["level-5"]["usd_amount"] == "64.00"
|
|
assert [tiers[f"level-{level}"]["level"] for level in range(1, 6)] == list(range(1, 6))
|
|
for name in ["membership", "membership-worker"]:
|
|
deployment = find(all_objects, "Deployment", name)
|
|
pod_checks(deployment["spec"]["template"]["spec"])
|
|
web = find(all_objects, "Deployment", "membership")["spec"]["template"]["spec"]["containers"][0]
|
|
assert "assert r.status==200" in web["readinessProbe"]["exec"]["command"][-1]
|
|
worker = find(all_objects, "Deployment", "membership-worker")
|
|
assert worker["spec"]["replicas"] == 1 and worker["spec"]["strategy"]["type"] == "Recreate"
|
|
assert "sync_memberships" in worker["spec"]["template"]["spec"]["containers"][0]["command"]
|
|
job = next(obj for obj in all_objects if obj["kind"] == "Job")
|
|
assert job["metadata"]["name"] == "membership-migrate-" + "a" * 16
|
|
pod_checks(job["spec"]["template"]["spec"])
|
|
assert job["spec"]["template"]["spec"]["containers"][0]["command"] == ["python", "manage.py", "migrate", "--noinput"]
|
|
db = find(all_objects, "StatefulSet", "membership-db")
|
|
assert db["spec"]["volumeClaimTemplates"][0]["spec"]["accessModes"] == ["ReadWriteOnce"]
|
|
assert "persistentVolumeClaimRetentionPolicy" not in db["spec"]
|
|
assert find(all_objects, "Service", "membership-db")["spec"]["type"] == "ClusterIP"
|
|
assert find(all_objects, "Service", "membership")["spec"]["type"] == "ClusterIP"
|
|
policy = find(all_objects, "NetworkPolicy", "membership-web")
|
|
assert policy["spec"]["ingress"][0]["from"] == [{"podSelector": {"matchLabels": {"app": "httpd"}}}]
|
|
apache = find(all_objects, "ConfigMap", "httpd")["data"]
|
|
assert "http://membership:8000/members/" in apache["membership.conf"]
|
|
assert "X-Forwarded-Proto" in apache["membership.conf"]
|
|
assert "Require all denied" in apache["membership.conf"]
|
|
assert "env=!membership_sensitive" in apache["httpd.conf"]
|
|
assert "LoadModule proxy_http_module" in apache["httpd.conf"]
|
|
source = find(all_objects, "Deployment", "httpd")["spec"]["template"]["spec"]["initContainers"][0]
|
|
assert "rm -rf" not in source["command"][-1]
|
|
assert 'cp -a /tmp/www/htdocs/. /data/' in source["command"][-1]
|
|
ingress = find(all_objects, "Ingress", "www")
|
|
assert ingress["metadata"]["annotations"]["nginx.ingress.kubernetes.io/enable-access-log"] == "false"
|
|
assert ingress["spec"]["rules"][0]["http"]["paths"][0]["backend"]["service"]["name"] == "httpd"
|
|
for obj in docs("external-membership-workloads"):
|
|
if obj["kind"] == "Deployment":
|
|
pod_checks(obj["spec"]["template"]["spec"], external=True)
|
|
external_config = docs("external-membership-config")
|
|
assert not any(obj["kind"] == "NetworkPolicy" and obj["metadata"]["name"] == "membership-db" for obj in external_config)
|
|
assert find(external_config, "ConfigMap", "membership-config")["data"]["POSTGRES_SSLMODE"] == "verify-full"
|
|
assert find(external_config, "ConfigMap", "membership-config")["data"]["LDAP_ALLOW_INSECURE"] == "0"
|
|
disabled = docs("disabled-website")
|
|
assert not any(obj["kind"] == "OnionService" for obj in disabled)
|
|
assert "ProxyPass" not in find(disabled, "ConfigMap", "httpd")["data"]["membership.conf"]
|
|
print(f"PASS: {len(all_objects)} Kubernetes objects; default, plaintext LDAP, external/CA/SHKeeper and disabled variants")
|