From 954abc68642ac65f3a99b618220f413af94abda8 Mon Sep 17 00:00:00 2001 From: ogt Date: Sat, 11 Jul 2026 01:56:16 +0800 Subject: [PATCH 1/2] 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 From aae5319a5f4532ded51052e4312c2697704bad78 Mon Sep 17 00:00:00 2001 From: AWOOOI CD Date: Sat, 11 Jul 2026 02:05:09 +0800 Subject: [PATCH 2/2] chore(cd): deploy 954abc6 [skip ci] --- k8s/awoooi-prod/06-deployment-api.yaml | 4 ++-- k8s/awoooi-prod/kustomization.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/k8s/awoooi-prod/06-deployment-api.yaml b/k8s/awoooi-prod/06-deployment-api.yaml index c086a09f3..550a49ea8 100644 --- a/k8s/awoooi-prod/06-deployment-api.yaml +++ b/k8s/awoooi-prod/06-deployment-api.yaml @@ -79,12 +79,12 @@ spec: - name: AWOOOI_BUILD_COMMIT_SHA # 2026-06-29 Codex: CD rewrites this to the deployed image tag so # production deploy readback does not rely on a stale static snapshot. - value: "de5e29360f3d1808daf0e0d0991aa3cce233f124" + value: "954abc68642ac65f3a99b618220f413af94abda8" - name: AWOOOI_DESIRED_API_IMAGE_TAG # 2026-06-30 Codex: CD rewrites this alongside AWOOOI_BUILD_COMMIT_SHA. # Production readback compares runtime image truth against this # GitOps desired tag instead of doing a slow Gitea raw fetch. - value: "de5e29360f3d1808daf0e0d0991aa3cce233f124" + value: "954abc68642ac65f3a99b618220f413af94abda8" - name: DATABASE_POOL_SIZE # 2026-07-01 Codex: production role `awoooi` currently has a low # connection limit. Keep API pool conservative until DB role diff --git a/k8s/awoooi-prod/kustomization.yaml b/k8s/awoooi-prod/kustomization.yaml index 23b6822e3..1664b4dcf 100644 --- a/k8s/awoooi-prod/kustomization.yaml +++ b/k8s/awoooi-prod/kustomization.yaml @@ -42,7 +42,7 @@ resources: images: - name: 192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER newName: 192.168.0.110:5000/awoooi/api - newTag: de5e29360f3d1808daf0e0d0991aa3cce233f124 + newTag: 954abc68642ac65f3a99b618220f413af94abda8 - name: 192.168.0.110:5000/library/web:IMAGE_TAG_PLACEHOLDER newName: 192.168.0.110:5000/awoooi/web - newTag: de5e29360f3d1808daf0e0d0991aa3cce233f124 + newTag: 954abc68642ac65f3a99b618220f413af94abda8