From 954abc68642ac65f3a99b618220f413af94abda8 Mon Sep 17 00:00:00 2001 From: ogt Date: Sat, 11 Jul 2026 01:56:16 +0800 Subject: [PATCH] fix(cd): snapshot live network policy for rollback --- .gitea/workflows/cd.yaml | 21 +++++++++++++++++-- .../test_executor_network_policy_boundary.py | 4 ++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 6dd6f378a..7da4b0659 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -2188,16 +2188,33 @@ jobs: # ─── Step 1: Apply NetworkPolicy + ConfigMap + ServiceRegistry ─── # NetworkPolicy is intentionally outside kustomize because commonLabels - # mutates nested selectors. Keep a source rollback artifact until the + # mutates nested selectors. Capture production truth before apply; the + # checkout is intentionally depth=1, so parent Git history is not a + # valid rollback source. Keep this artifact until the # live socket and public receipt verifiers have both passed. NETWORK_POLICY_ROLLBACK_FILE="/tmp/awoooi-network-policy-rollback.yaml" - git show HEAD^:k8s/awoooi-prod/02-network-policy.yaml \ + BROKER_POLICY_NAME="allow-ansible-executor-broker-ssh-egress" + BROKER_POLICY_EXISTED=$(ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ + "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; if \$KUBECTL get networkpolicy '$BROKER_POLICY_NAME' -n awoooi-prod >/dev/null 2>&1; then printf 1; else printf 0; fi") + ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ + "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL get networkpolicy default-deny-all allow-nginx-ingress allow-required-egress deny-legacy-access -n awoooi-prod -o yaml" \ > "$NETWORK_POLICY_ROLLBACK_FILE" + if [ "$BROKER_POLICY_EXISTED" = "1" ]; then + printf '\n---\n' >> "$NETWORK_POLICY_ROLLBACK_FILE" + ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ + "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL get networkpolicy '$BROKER_POLICY_NAME' -n awoooi-prod -o yaml" \ + >> "$NETWORK_POLICY_ROLLBACK_FILE" + fi + test -s "$NETWORK_POLICY_ROLLBACK_FILE" restore_network_policy() { echo "⏪ restoring previous AWOOOI NetworkPolicy contract" cat "$NETWORK_POLICY_ROLLBACK_FILE" | \ ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL apply -f -" + if [ "$BROKER_POLICY_EXISTED" = "0" ]; then + ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ + "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL delete networkpolicy '$BROKER_POLICY_NAME' -n awoooi-prod --ignore-not-found=true" + fi } cat k8s/awoooi-prod/02-network-policy.yaml | \ ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ diff --git a/apps/api/tests/test_executor_network_policy_boundary.py b/apps/api/tests/test_executor_network_policy_boundary.py index 29f772255..cc4dbaf25 100644 --- a/apps/api/tests/test_executor_network_policy_boundary.py +++ b/apps/api/tests/test_executor_network_policy_boundary.py @@ -70,6 +70,10 @@ def test_cd_applies_rolls_back_and_verifies_network_boundary() -> None: assert "02-network-policy.yaml" in workflow assert "NETWORK_POLICY_ROLLBACK_FILE" in workflow + assert "git show HEAD^:k8s/awoooi-prod/02-network-policy.yaml" not in workflow + assert "BROKER_POLICY_EXISTED" in workflow + assert "$KUBECTL get networkpolicy default-deny-all" in workflow + assert "$KUBECTL delete networkpolicy '$BROKER_POLICY_NAME'" in workflow assert "allow-ansible-executor-broker-ssh-egress" in workflow assert "api_ssh_egress_denied=true" in workflow assert "worker_ssh_egress_denied=true" in workflow