219 lines
10 KiB
YAML
219 lines
10 KiB
YAML
---
|
|
# 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 }}"
|