Files
svg-backend/backend/scripts/smoke_authz_admin_all.sh
greebo 54b36ba76c chore(backend): finalize backend baseline and frontend handoff contract
freeze the current backend contract for frontend integration

document the stabilized backend surface and handoff expectations
mark the current state as the baseline for further frontend work
2026-03-20 16:46:24 +03:00

203 lines
12 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT
# shellcheck source=backend/scripts/smoke_common.sh
source "${SCRIPT_DIR}/smoke_common.sh"
ADMIN_API_KEY="${ADMIN_API_KEY:-admin-local-dev-key}"
OPERATOR_API_KEY="${OPERATOR_API_KEY:-operator-local-dev-key}"
VIEWER_API_KEY="${VIEWER_API_KEY:-viewer-local-dev-key}"
wait_for_health
create_fresh_scheme_from_upload "smoke-authz-admin-all"
request "scheme_current" "GET" "${API_URL}/api/v1/schemes/${SCHEME_ID}/current" "200"
CURRENT_VERSION_ID="$(json_get "${TMP_DIR}/scheme_current.body" "scheme_version_id")"
echo "CURRENT_VERSION_ID=${CURRENT_VERSION_ID}"
request "ensure_draft" "POST" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/draft/ensure?expected_current_scheme_version_id=${CURRENT_VERSION_ID}" \
"200"
DRAFT_VERSION_ID="$(json_get "${TMP_DIR}/ensure_draft.body" "scheme_version_id")"
echo "DRAFT_VERSION_ID=${DRAFT_VERSION_ID}"
request "draft_structure" "GET" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/draft/structure?expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200"
TARGET_SEAT_ID="$(python3 - "${TMP_DIR}/draft_structure.body" <<'PY'
import json
import sys
from pathlib import Path
payload = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
seat = next((item for item in payload.get("seats", []) if item.get("seat_id")), None)
if seat is None:
raise SystemExit("No seat with seat_id found for authz admin all smoke")
print(seat["seat_id"])
PY
)"
echo "TARGET_SEAT_ID=${TARGET_SEAT_ID}"
STAMP="$(date +%s)-$$"
CLEANUP_PREFIX="AUTHZ_ADMINALL_${STAMP}_"
DELETE_CATEGORY_NAME="authz-adminall-delete-${STAMP}"
DELETE_CATEGORY_CODE="${CLEANUP_PREFIX}DELETE"
KEEP_CATEGORY_NAME="authz-adminall-keep-${STAMP}"
KEEP_CATEGORY_CODE="${CLEANUP_PREFIX}KEEP"
request "create_delete_category" "POST" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/pricing/categories?expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200" \
"{\"name\":\"${DELETE_CATEGORY_NAME}\",\"code\":\"${DELETE_CATEGORY_CODE}\"}"
DELETE_CATEGORY_ID="$(json_get "${TMP_DIR}/create_delete_category.body" "pricing_category_id")"
echo "DELETE_CATEGORY_ID=${DELETE_CATEGORY_ID}"
request "create_keep_category" "POST" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/pricing/categories?expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200" \
"{\"name\":\"${KEEP_CATEGORY_NAME}\",\"code\":\"${KEEP_CATEGORY_CODE}\"}"
KEEP_CATEGORY_ID="$(json_get "${TMP_DIR}/create_keep_category.body" "pricing_category_id")"
echo "KEEP_CATEGORY_ID=${KEEP_CATEGORY_ID}"
request "create_keep_category_rule" "POST" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/pricing/rules?expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200" \
"{\"pricing_category_id\":\"${KEEP_CATEGORY_ID}\",\"target_type\":\"seat\",\"target_ref\":\"${TARGET_SEAT_ID}\",\"amount\":\"777.00\",\"currency\":\"RUB\"}"
KEEP_RULE_ID="$(json_get "${TMP_DIR}/create_keep_category_rule.body" "price_rule_id")"
echo "KEEP_RULE_ID=${KEEP_RULE_ID}"
request "draft_pricing_snapshot" "POST" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/draft/pricing/snapshot?expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200"
request "publish_preview_refresh" "GET" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/draft/publish-preview?refresh=true&expected_scheme_version_id=${DRAFT_VERSION_ID}" \
"200"
request_with_api_key "${ADMIN_API_KEY}" "admin_current_artifacts" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/artifacts" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_current_artifacts" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/artifacts" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_current_artifacts" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/artifacts" "403"
assert_file_contains "${TMP_DIR}/operator_current_artifacts.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_current_artifacts.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_current_validation" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/validation" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_current_validation" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/validation" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_current_validation" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/validation" "403"
assert_file_contains "${TMP_DIR}/operator_current_validation.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_current_validation.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_display_regenerate" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/display/regenerate?mode=passthrough" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_display_regenerate" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/display/regenerate?mode=passthrough" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_display_regenerate" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/current/display/regenerate?mode=passthrough" "403"
assert_file_contains "${TMP_DIR}/operator_display_regenerate.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_display_regenerate.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_display_backfill" "POST" \
"${API_URL}/api/v1/admin/display/backfill?mode=passthrough&limit=1&only_missing=true" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_display_backfill" "POST" \
"${API_URL}/api/v1/admin/display/backfill?mode=passthrough&limit=1&only_missing=true" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_display_backfill" "POST" \
"${API_URL}/api/v1/admin/display/backfill?mode=passthrough&limit=1&only_missing=true" "403"
assert_file_contains "${TMP_DIR}/operator_display_backfill.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_display_backfill.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_publish_preview_audit" "GET" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/audit" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_publish_preview_audit" "GET" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/audit" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_publish_preview_audit" "GET" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/audit" "403"
assert_file_contains "${TMP_DIR}/operator_publish_preview_audit.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_publish_preview_audit.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_publish_preview_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/cleanup?dry_run=true" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_publish_preview_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/cleanup?dry_run=true" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_publish_preview_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/artifacts/publish-preview/cleanup?dry_run=true" "403"
assert_file_contains "${TMP_DIR}/operator_publish_preview_cleanup_dry_run.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_publish_preview_cleanup_dry_run.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_pricing_cleanup_preview" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup-preview?code_prefix=${CLEANUP_PREFIX}" "200"
request_with_api_key "${OPERATOR_API_KEY}" "operator_pricing_cleanup_preview" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup-preview?code_prefix=${CLEANUP_PREFIX}" "403"
request_with_api_key "${VIEWER_API_KEY}" "viewer_pricing_cleanup_preview" "GET" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup-preview?code_prefix=${CLEANUP_PREFIX}" "403"
assert_file_contains "${TMP_DIR}/operator_pricing_cleanup_preview.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_pricing_cleanup_preview.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_pricing_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "200" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":true}"
request_with_api_key "${OPERATOR_API_KEY}" "operator_pricing_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "403" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":true}"
request_with_api_key "${VIEWER_API_KEY}" "viewer_pricing_cleanup_dry_run" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "403" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":true}"
assert_file_contains "${TMP_DIR}/operator_pricing_cleanup_dry_run.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_pricing_cleanup_dry_run.body" "Admin role required"
request_with_api_key "${OPERATOR_API_KEY}" "operator_pricing_cleanup_execute" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "403" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":false}"
request_with_api_key "${VIEWER_API_KEY}" "viewer_pricing_cleanup_execute" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "403" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":false}"
assert_file_contains "${TMP_DIR}/operator_pricing_cleanup_execute.body" "Admin role required"
assert_file_contains "${TMP_DIR}/viewer_pricing_cleanup_execute.body" "Admin role required"
request_with_api_key "${ADMIN_API_KEY}" "admin_pricing_cleanup_execute" "POST" \
"${API_URL}/api/v1/admin/schemes/${SCHEME_ID}/pricing/categories/cleanup" "200" \
"{\"code_prefixes\":[\"${CLEANUP_PREFIX}\"],\"name_prefixes\":[],\"pricing_category_ids\":[],\"delete_only_without_rules\":true,\"dry_run\":false}"
assert_json_int_eq "${TMP_DIR}/admin_pricing_cleanup_execute.body" "deleted_count" "1"
assert_json_int_eq "${TMP_DIR}/admin_pricing_cleanup_execute.body" "skipped_count" "1"
request "pricing_bundle_after_admin_cleanup_execute" "GET" \
"${API_URL}/api/v1/schemes/${SCHEME_ID}/pricing" "200"
assert_json_len_eq "${TMP_DIR}/pricing_bundle_after_admin_cleanup_execute.body" "categories" "1"
assert_json_len_eq "${TMP_DIR}/pricing_bundle_after_admin_cleanup_execute.body" "rules" "1"
python3 - "${TMP_DIR}/pricing_bundle_after_admin_cleanup_execute.body" "${DELETE_CATEGORY_ID}" "${KEEP_CATEGORY_ID}" "${KEEP_RULE_ID}" <<'PY'
import json
import sys
from pathlib import Path
payload = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
delete_category_id = sys.argv[2]
keep_category_id = sys.argv[3]
keep_rule_id = sys.argv[4]
category_ids = {item["pricing_category_id"] for item in payload.get("categories", [])}
rule_ids = {item["price_rule_id"] for item in payload.get("rules", [])}
if delete_category_id in category_ids:
raise SystemExit("Authz admin-all cleanup left deletable category behind")
if keep_category_id not in category_ids:
raise SystemExit("Authz admin-all cleanup removed protected category")
if keep_rule_id not in rule_ids:
raise SystemExit("Authz admin-all cleanup removed protected rule")
PY
echo "[OK] admin cleanup execute remained destructive only for safe fixture category"
echo
echo "===== done ====="
echo "[OK] smoke authz admin all completed successfully"
echo "FRESH_SCHEME_ID=${SCHEME_ID}"