Merge remote-tracking branch 'origin/main' into codex/ai-automation-codebase-review-20260710

# Conflicts:
#	.gitea/workflows/cd.yaml
#	apps/api/tests/test_executor_network_policy_boundary.py
This commit is contained in:
ogt
2026-07-11 02:14:03 +08:00
4 changed files with 61 additions and 18 deletions

View File

@@ -2188,13 +2188,14 @@ jobs:
# ─── Step 1: Apply NetworkPolicy + ConfigMap + ServiceRegistry ───
# NetworkPolicy is intentionally outside kustomize because commonLabels
# mutates nested selectors. Keep a live rollback artifact until the
# live socket and public receipt verifiers have both passed.
# The runner checkout is intentionally single-commit, so HEAD^ is not
# available here. Snapshot live policy truth before any mutation.
# mutates nested selectors. The checkout is depth=1, so snapshot live
# policy truth and remove server-only metadata before any mutation.
NETWORK_POLICY_ROLLBACK_FILE="/tmp/awoooi-network-policy-rollback.json"
NETWORK_POLICY_LIVE_RAW_FILE="/tmp/awoooi-network-policy-live.json"
NETWORK_POLICY_CHANGE_ACTIVE="0"
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 -n awoooi-prod -o json" \
> "$NETWORK_POLICY_LIVE_RAW_FILE"
@@ -2250,10 +2251,20 @@ jobs:
if 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 -"; then
NETWORK_POLICY_CHANGE_ACTIVE="0"
return 0
restore_status="0"
else
restore_status="$?"
fi
return 1
if [ "$BROKER_POLICY_EXISTED" = "0" ]; then
if ! 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"; then
restore_status="1"
fi
fi
if [ "$restore_status" = "0" ]; then
NETWORK_POLICY_CHANGE_ACTIVE="0"
fi
return "$restore_status"
}
rollback_network_policy_on_exit() {
exit_code=$?
@@ -2533,6 +2544,30 @@ jobs:
# AIA-P0-011: production must prove that the public API cannot mutate
# workloads or read host executor credentials. Source YAML alone is
# insufficient because stale SSA-owned list fields can survive sync.
auth_can_i() {
local output
local status
local answer
set +e
output=$($KUBECTL auth can-i "$@" 2>&1)
status=$?
set -e
answer=$(printf '%s\n' "$output" | tail -1 | tr -d '\r')
case "$answer" in
yes|no)
printf '%s' "$answer"
return 0
;;
*)
echo "❌ kubectl auth can-i returned an invalid response: $output" >&2
if [ "$status" -eq 0 ]; then
status=1
fi
return "$status"
;;
esac
}
echo "executor_boundary_stage=collect_live_identity_and_policy"
API_SA=$($KUBECTL get deployment/awoooi-api -n awoooi-prod \
-o jsonpath='{.spec.template.spec.serviceAccountName}')
WORKER_SA=$($KUBECTL get deployment/awoooi-worker -n awoooi-prod \
@@ -2559,25 +2594,25 @@ jobs:
-o jsonpath='{.spec.template.spec.containers[?(@.name=="api")].env[?(@.name=="ENABLE_AWOOOP_ANSIBLE_CHECK_MODE_WORKER")].value}')
API_BACKFILL_WORKER=$($KUBECTL get deployment/awoooi-api -n awoooi-prod \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="api")].env[?(@.name=="ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER")].value}')
API_CAN_GET=$($KUBECTL auth can-i \
API_CAN_GET=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-api \
get pods --all-namespaces)
API_CAN_PATCH=$($KUBECTL auth can-i \
API_CAN_PATCH=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-api \
patch deployments.apps --all-namespaces)
API_CAN_DELETE=$($KUBECTL auth can-i \
API_CAN_DELETE=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-api \
delete pods --all-namespaces)
WORKER_CAN_PATCH=$($KUBECTL auth can-i \
WORKER_CAN_PATCH=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-worker \
patch deployments.apps --all-namespaces)
WORKER_CAN_DELETE=$($KUBECTL auth can-i \
WORKER_CAN_DELETE=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-worker \
delete pods --all-namespaces)
BROKER_CAN_PATCH=$($KUBECTL auth can-i \
BROKER_CAN_PATCH=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-executor-broker \
patch deployments.apps --all-namespaces)
BROKER_CAN_DELETE=$($KUBECTL auth can-i \
BROKER_CAN_DELETE=$(auth_can_i \
--as=system:serviceaccount:awoooi-prod:awoooi-executor-broker \
delete pods --all-namespaces)
COMMON_SSH_PORT_COUNT=$($KUBECTL get networkpolicy \
@@ -2687,6 +2722,7 @@ jobs:
test "$LEGACY_EGRESS_RULE_COUNT" = "0" || {
echo "❌ legacy namespace policy still creates an allow rule"; exit 1;
}
echo "executor_boundary_stage=static_identity_and_policy_verified"
verify_ssh_denied() {
workload="$1"
@@ -2739,6 +2775,7 @@ jobs:
verify_broker_ssh_allowed || {
echo "❌ execution broker cannot reach any allowlisted SSH endpoint"; exit 1;
}
echo "executor_boundary_stage=live_socket_boundary_verified"
BOUNDARY_VERIFIED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
$KUBECTL create configmap awoooi-executor-boundary-verification \

View File

@@ -73,6 +73,12 @@ def test_cd_applies_rolls_back_and_verifies_network_boundary() -> None:
assert "get networkpolicy -n awoooi-prod -o json" in workflow
assert "rollback_network_policy_on_exit" in workflow
assert "git show HEAD^:k8s/awoooi-prod/02-network-policy.yaml" not in workflow
assert "BROKER_POLICY_EXISTED" in workflow
assert "$KUBECTL delete networkpolicy '$BROKER_POLICY_NAME'" in workflow
assert "auth_can_i()" in workflow
assert "API_CAN_PATCH=$(auth_can_i" in workflow
assert "BROKER_CAN_DELETE=$(auth_can_i" in workflow
assert "executor_boundary_stage=live_socket_boundary_verified" 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

View File

@@ -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

View File

@@ -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