#!/usr/bin/env bash # Spec 027 — valida enum RBAC, módulos por função e endpoints críticos set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ENV_FILE="${ENV_FILE:-/opt/ligbox-ops-platform/.env}" if [[ -f "$ENV_FILE" ]]; then set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a fi API="${API_URL:-http://10.10.10.122:8080}" PASS="${DESK_BOOTSTRAP_PASSWORD:-805353}" echo "=== verify-rbac-matrix.sh === API=$API" fail() { echo "FAIL: $1"; exit 1; } ok() { echo "OK: $1"; } echo "--- unit tests permissions 027 ---" python3 "$ROOT/api/tests/test_permissions_027.py" || fail "unit tests permissions" ok "python unit tests" login_token() { local user=$1 curl -sf -X POST "$API/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d "{\"username\":\"$user\",\"password\":\"$PASS\"}" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])" } TOKEN_ROOT=$(login_token root) ok "login root" roles_json=$(curl -sf -H "Authorization: Bearer $TOKEN_ROOT" "$API/api/v1/auth/roles") echo "$roles_json" | python3 -c " import json, sys d = json.load(sys.stdin) assignable = d.get('assignable') or [] labels = d.get('labels') or {} for r in ('sales_admin', 'sales_support', 'finance', 'agentic_operator'): assert r in assignable, f'missing assignable role {r}' assert r in labels, f'missing label {r}' print('assignable', len(assignable)) " || fail "GET /auth/roles" ok "GET /auth/roles — sales_admin/sales_support/finance presentes" modules_json=$(curl -sf -H "Authorization: Bearer $TOKEN_ROOT" "$API/api/v1/modules") echo "$modules_json" | python3 -c " import json, sys d = json.load(sys.stdin) mods = {m['id']: m for m in d.get('modules', [])} assert 'enabled_for_role' in next(iter(mods.values()), {}), 'enabled_for_role missing' " || fail "modules schema" ok "GET /modules — enabled_for_role" code=$(curl -s -o /dev/null -w '%{http_code}' \ -H "Authorization: Bearer $TOKEN_ROOT" \ "$API/api/v1/billing/summary") [[ "$code" == "200" ]] || fail "root billing summary (got $code)" ok "root GET /billing/summary" if TOKEN_ADMIN=$(login_token admin 2>/dev/null); then code=$(curl -s -o /dev/null -w '%{http_code}' \ -H "Authorization: Bearer $TOKEN_ADMIN" \ -X PATCH -H "Content-Type: application/json" \ -d '{"billing_state":"billing_active"}' \ "$API/api/v1/billing/accounts/1") [[ "$code" == "403" || "$code" == "404" ]] || fail "ops_lead PATCH billing devia 403/404 (got $code)" ok "ops_lead PATCH billing → $code (sem permissão de validação)" else echo "SKIP: user admin não disponível" fi if TOKEN_NOC=$(login_token noc 2>/dev/null); then curl -sf -H "Authorization: Bearer $TOKEN_NOC" "$API/api/v1/billing/summary" >/dev/null || fail "noc billing read" ok "noc GET /billing/summary (read masked)" else echo "SKIP: user noc não disponível" fi echo "=== verify-rbac-matrix.sh PASSED ==="