--- # Offline tests: no Kubernetes credentials or API calls. - name: Validate role configuration and rendered Kubernetes resources hosts: localhost connection: local gather_facts: false vars_files: - ../defaults/main.yml tasks: - name: Test rendering variants ansible.builtin.include_tasks: render_case.yml vars: wikideck_image: "{{ render_case.image | default('registry.example.com/wikideck:1.0.0') }}" wikideck_name: "{{ render_case.name | default('wikideck') }}" wikideck_namespace: "{{ render_case.namespace | default('wikideck') }}" wikideck_image_pull_policy: "{{ render_case.pull_policy | default('IfNotPresent') }}" wikideck_pod_annotations: "{{ render_case.pod_annotations | default({}) }}" wikideck_peers: "{{ render_case.peers | default([]) }}" wikideck_allow_private_peers: "{{ render_case.allow_private | default(false) }}" wikideck_mainnet_launch: "{{ render_case.mainnet_launch | default('') }}" wikideck_mainnet_risk_ack: "{{ render_case.risk_ack | default('') }}" wikideck_trusted_proxies: "{{ render_case.trusted_proxies | default([]) }}" wikideck_ops_port: "{{ render_case.ops_port | default('') }}" wikideck_startup_probe_failure_threshold: "{{ render_case.startup_threshold | default(180) }}" wikideck_ingress_enabled: "{{ render_case.ingress | default(false) }}" wikideck_ingress_host: wikideck.example.com wikideck_public_origin: "{{ 'https://wikideck.example.com' if render_case.ingress | default(false) else '' }}" wikideck_ingress_class_name: "{{ render_case.ingress_class | default('') }}" wikideck_ingress_annotations: "{{ render_case.annotations | default({}) }}" wikideck_storage_class: "{{ render_case.storage_class | default(none) }}" wikideck_existing_claim: "{{ render_case.existing_claim | default('') }}" wikideck_image_pull_secrets: "{{ render_case.pull_secrets | default([]) }}" wikideck_network_policy_ingress_from: "{{ render_case.ingress_from | default([{'podSelector': {}}]) }}" wikideck_network_policy_dns_to: "{{ render_case.dns_to | default([{'namespaceSelector': {}}]) }}" wikideck_network_policy_https_to: "{{ render_case.https_to | default([{'ipBlock': {'cidr': '0.0.0.0/0'}}]) }}" wikideck_network_policy_https_ports: "{{ render_case.https_ports | default([443]) }}" wikideck_network_policy_peer_egress: "{{ render_case.peer_egress | default([]) }}" loop: - label: isolated validator defaults - label: TLS ingress and existing storage peers: [https://peer-a.example.org, https://peer-b.example.org] ingress: true ingress_class: nginx annotations: cert-manager.io/cluster-issuer: letsencrypt-prod existing_claim: existing-chain storage_class: fast-encrypted pull_secrets: [registry-credentials] name: custom-deck namespace: games - label: isolated validator and no storage class storage_class: "" - label: default-deny all traffic ingress_from: [] dns_to: [] https_to: [] - label: public peers with custom HTTPS port and long startup peers: [https://peer.example.org:8443] https_ports: [443, 8443] startup_threshold: 360 - label: private HTTP testnet with restricted egress peers: [http://other-node.games.svc.cluster.local:80] allow_private: true https_to: [] peer_egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: games podSelector: matchLabels: app.kubernetes.io/instance: other-node ports: - protocol: TCP port: 3001 - label: public peer with all egress explicitly denied peers: [https://peer.example.org] dns_to: [] https_to: [] - label: digest-pinned image image: registry.example.com/wikideck@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - label: proxy trust and private diagnostics peers: [https://peer-a.example.org, https://peer-b.example.org] trusted_proxies: [10.20.30.40, 2001:db8::/64] ops_port: "9090" - label: exact mainnet launch configuration mainnet_launch: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa risk_ack: operator-accepts-unaudited-risk - label: latest private mainnet candidate public node image: ericomeehan/wikideck:latest pull_policy: Always pod_annotations: wikideck.eom.dev/image-id: docker-pullable://ericomeehan/wikideck@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa peers: [http://wikideck-peer-a.wikideck.svc.cluster.local:80, http://wikideck-peer-b.wikideck.svc.cluster.local:80] allow_private: true ingress: true mainnet_launch: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa risk_ack: operator-accepts-unaudited-risk # Public HTTPS is needed for Wikipedia mining templates and statistics. https_to: - ipBlock: cidr: 0.0.0.0/0 except: [10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16] - ipBlock: cidr: "::/0" except: ["::1/128", "fc00::/7", "fe80::/10"] ingress_from: - podSelector: matchLabels: app.kubernetes.io/name: wikideck - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ingress-nginx peer_egress: - to: - podSelector: matchLabels: app.kubernetes.io/name: wikideck ports: [{protocol: TCP, port: 3001}] - label: latest private mainnet candidate internal peer image: ericomeehan/wikideck:latest pull_policy: Always name: wikideck-peer-a peers: [http://wikideck.wikideck.svc.cluster.local:80, http://wikideck-peer-b.wikideck.svc.cluster.local:80] allow_private: true mainnet_launch: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa risk_ack: operator-accepts-unaudited-risk https_to: [] peer_egress: - to: - podSelector: matchLabels: app.kubernetes.io/name: wikideck ports: [{protocol: TCP, port: 3001}] loop_control: loop_var: render_case label: "{{ render_case.label }}" - name: Test invalid settings are rejected ansible.builtin.include_tasks: invalid_case.yml loop: - label: missing image image: "" - label: untagged image image: registry.example.com/wikideck - label: registry port is not an image tag image: registry.example.com:5000/wikideck - label: malformed image digest image: registry.example.com/wikideck@sha256:abcd - label: invalid resource name name: Invalid_Name - label: unsafe multi-writer storage access_modes: [ReadWriteMany] - label: missing ingress origin ingress: true - label: mismatched ingress origin ingress: true origin: https://another.example.com - label: insecure public origin origin: http://wikideck.example.com - label: origin with path origin: https://wikideck.example.com/path - label: invalid ingress hostname ingress: true host: invalid_host origin: https://wikideck.example.com - label: missing resource limits resources: requests: {cpu: 100m, memory: 128Mi} - label: ambiguous boolean allow_private: "false" - label: wrong list type pull_secrets: not-a-list - label: empty peer allows all traffic ingress_from: [{}] - label: too many peers peers: [https://a.example.org, https://b.example.org, https://c.example.org, https://d.example.org, https://e.example.org, https://f.example.org, https://g.example.org, https://h.example.org, https://i.example.org, https://j.example.org, https://k.example.org, https://l.example.org, https://m.example.org, https://n.example.org, https://o.example.org, https://p.example.org, https://q.example.org] - label: peers must be a list peers: https://peer.example.org - label: HTTP peers need explicit opt-in peers: [http://peer.example.org] - label: credentials in peer URL peers: [https://user:password@peer.example.org] - label: path in peer URL peers: [https://peer.example.org/p2p] - label: query in peer URL peers: ['https://peer.example.org?x=1'] - label: comma can inject a second peer peers: ['https://peer.example.org,https://another.example.org'] - label: zero startup threshold startup_threshold: 0 - label: invalid HTTPS egress port https_ports: [65536] - label: egress rule without destinations peer_egress: - ports: [{protocol: TCP, port: 3001}] - label: egress rule without ports peer_egress: - to: [{podSelector: {}}] - label: egress rule with an empty peer peer_egress: - to: [{}] ports: [{protocol: TCP, port: 3001}] - label: non-TCP peer egress peer_egress: - to: [{podSelector: {}}] ports: [{protocol: UDP, port: 3001}] - label: malformed mainnet chain approval mainnet_launch: not-a-chain-id - label: unsupported mainnet risk acknowledgement risk_ack: operator-accepts-risk - label: proxy entry is not an IP or CIDR trusted_proxies: [proxy.example.org] - label: operations port out of range ops_port: "70000" loop_control: loop_var: invalid_case label: "{{ invalid_case.label }}"