Files
fission-console/scripts/test_isolation.sh
T

163 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# test_isolation.sh — тестирует namespace изоляцию:
# Пользователь A не видит и не может изменить функции пользователя B.
# LIST каждого пользователя возвращает только его функции.
set -uo pipefail
ROOT_DIR=$(cd "$(dirname "$0")" && pwd)
source "${ROOT_DIR}/lib.sh"
NS_CLEANUP_SCRIPT="${ROOT_DIR}/cleanup_test_namespaces.sh"
RUN_ID=$(mk_run_id)
ALICE="test-alice-${RUN_ID}@test.local"
BOB="test-bob-${RUN_ID}@test.local"
cleanup() {
if [ -x "$NS_CLEANUP_SCRIPT" ]; then
KUBECTL_DIRECT=1 "$NS_CLEANUP_SCRIPT" "$ALICE" "$BOB" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
echo ""
echo "========================================"
echo " test_isolation.sh run=$RUN_ID"
echo "========================================"
JS_CODE='module.exports = async function() { return { status: 200, body: "ok" }; }'
# ── Alice создаёт функцию ─────────────────────────────────────────────────────
echo ""
echo ">>> Alice создаёт функцию"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${ALICE}" -H "Content-Type: application/json" \
-d "{\"name\":\"t-alice-fn\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}")
check_http "$(echo "$R" | tail -1)" "201" "Alice CREATE t-alice-fn → 201"
# ── Bob не может получить функцию Alice ──────────────────────────────────────
echo ""
echo ">>> Bob GET t-alice-fn → 404"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions/t-alice-fn" \
-H "X-Auth-Token: ${BOB}")
check_http "$(echo "$R" | tail -1)" "404" "Bob GET t-alice-fn → 404"
echo ""
echo ">>> Bob DELETE t-alice-fn → 404"
R=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE}/functions/t-alice-fn" \
-H "X-Auth-Token: ${BOB}")
check_http "$(echo "$R" | tail -1)" "404" "Bob DELETE t-alice-fn → 404"
echo ""
echo ">>> Bob PUT t-alice-fn/code → 404"
R=$(curl -s -w "\n%{http_code}" -X PUT "${BASE}/functions/t-alice-fn/code" \
-H "X-Auth-Token: ${BOB}" -H "Content-Type: application/json" \
-d '{"code":"module.exports = async () => ({ body: \"hacked\" });"}')
check_http "$(echo "$R" | tail -1)" "404" "Bob PUT t-alice-fn/code → 404"
echo ""
echo ">>> Bob INVOKE t-alice-fn → 404"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions/t-alice-fn/invoke" \
-H "X-Auth-Token: ${BOB}" -H "Content-Type: application/json" -d '{}')
check_http "$(echo "$R" | tail -1)" "404" "Bob INVOKE t-alice-fn → 404"
# ── Alice убеждается что её функция цела ────────────────────────────────────
echo ""
echo ">>> Alice GET t-alice-fn → 200 (не повреждена)"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions/t-alice-fn" \
-H "X-Auth-Token: ${ALICE}")
check_http "$(echo "$R" | tail -1)" "200" "Alice GET t-alice-fn → 200"
# ── LIST изоляция ────────────────────────────────────────────────────────────
echo ""
echo ">>> LIST изоляция: Alice и Bob видят только свои функции"
# Bob создаёт свою функцию
curl -s -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${BOB}" -H "Content-Type: application/json" \
-d "{\"name\":\"t-bob-fn\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}" > /dev/null
sleep 1
ALICE_LIST=$(curl -s "${BASE}/functions" -H "X-Auth-Token: ${ALICE}")
BOB_LIST=$(curl -s "${BASE}/functions" -H "X-Auth-Token: ${BOB}")
# Alice видит t-alice-fn но не t-bob-fn
ALICE_COUNT=$(json_len "$ALICE_LIST")
ALICE_HAS_OWN=$(printf '%s' "$ALICE_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
print(sum(1 for f in fns if f.get('metadata',{}).get('name','') == 't-alice-fn'))
except:
print(0)" 2>/dev/null)
ALICE_HAS_BOB=$(printf '%s' "$ALICE_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
print(sum(1 for f in fns if f.get('metadata',{}).get('name','') == 't-bob-fn'))
except:
print(0)" 2>/dev/null)
[ "${ALICE_HAS_OWN:-0}" -ge 1 ] && pass "Alice LIST содержит t-alice-fn" || fail "Alice LIST не содержит t-alice-fn (count=$ALICE_COUNT)"
[ "${ALICE_HAS_BOB:-0}" -eq 0 ] && pass "Alice LIST не содержит t-bob-fn" || fail "Alice LIST содержит t-bob-fn — УТЕЧКА ДАННЫХ!"
# Bob видит t-bob-fn но не t-alice-fn
BOB_HAS_OWN=$(printf '%s' "$BOB_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
print(sum(1 for f in fns if f.get('metadata',{}).get('name','') == 't-bob-fn'))
except:
print(0)" 2>/dev/null)
BOB_HAS_ALICE=$(printf '%s' "$BOB_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
print(sum(1 for f in fns if f.get('metadata',{}).get('name','') == 't-alice-fn'))
except:
print(0)" 2>/dev/null)
[ "${BOB_HAS_OWN:-0}" -ge 1 ] && pass "Bob LIST содержит t-bob-fn" || fail "Bob LIST не содержит t-bob-fn"
[ "${BOB_HAS_ALICE:-0}" -eq 0 ] && pass "Bob LIST не содержит t-alice-fn" || fail "Bob LIST содержит t-alice-fn — УТЕЧКА ДАННЫХ!"
# ── Route изоляция ───────────────────────────────────────────────────────────
echo ""
echo ">>> Route изоляция: одинаковое имя → разные routes"
ROUTE_A=$(printf '%s' "$ALICE_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
for f in fns:
if f.get('metadata',{}).get('name','') == 't-alice-fn':
print(f.get('spec',{}).get('relativeurl',''))
break
except:
print('')" 2>/dev/null)
ROUTE_B=$(printf '%s' "$BOB_LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
for f in fns:
if f.get('metadata',{}).get('name','') == 't-bob-fn':
print(f.get('spec',{}).get('relativeurl',''))
break
except:
print('')" 2>/dev/null)
# Проверяем через GET (возвращает route)
ALICE_GET=$(curl -s "${BASE}/functions/t-alice-fn" -H "X-Auth-Token: ${ALICE}")
BOB_GET=$(curl -s "${BASE}/functions/t-bob-fn" -H "X-Auth-Token: ${BOB}")
ROUTE_A=$(json_field "$ALICE_GET" route)
ROUTE_B=$(json_field "$BOB_GET" route)
[ "$ROUTE_A" != "$ROUTE_B" ] && [ -n "$ROUTE_A" ] && [ -n "$ROUTE_B" ] \
&& pass "Route изоляция: $ROUTE_A$ROUTE_B" \
|| fail "Route коллизия: alice=$ROUTE_A bob=$ROUTE_B"
print_summary