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:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user