Files
vpd-permission-poc/scripts/vpd-ords-regression-test.sh

181 lines
6.2 KiB
Bash

#!/usr/bin/env bash
# VPD/Redaction ORDS regression test for the backoffice demo objects.
set -Eeuo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
if [[ -f "$ROOT/.env" ]]; then
# shellcheck disable=SC1091
set -a; . "$ROOT/.env"; set +a
fi
SQLCL_BIN="${SQLCL_BIN:-}"
if [[ -z "$SQLCL_BIN" ]]; then
SQLCL_BIN="$(command -v sql || true)"
fi
if [[ -z "$SQLCL_BIN" || ! -x "$SQLCL_BIN" ]]; then
echo "[FAIL] SQLcl 실행 파일을 찾을 수 없습니다. SQLCL_BIN=/path/to/sql 로 지정하세요." >&2
exit 1
fi
if [[ -n "${SQLCL_JAVA_HOME:-}" ]]; then
export JAVA_HOME="$SQLCL_JAVA_HOME"
fi
DB_USER="${BACKOFFICE_DB_USERNAME:-${ADB_USER:-}}"
DB_PASSWORD="${BACKOFFICE_DB_PASSWORD:-${ADB_PASSWORD:-}}"
DB_TNS="${ADB_TNS:-}"
ORDS_BASE="${BACKOFFICE_ORDS_BASE_URL:-https://yh0olybn5pqce4n-d8aukro81636mon0.adb.ap-seoul-1.oraclecloudapps.com/ords}"
ORDS_PATH="${BACKOFFICE_REGRESSION_ORDS_PATH:-cb-ords/cb-agent-security/vpd/documents}"
DESCRIPTION="codex issue458 regression"
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vpd-ords-regression.XXXXXX")"
require_value() {
local name="$1" value="$2"
if [[ -z "$value" ]]; then
echo "[FAIL] $name 값이 필요합니다." >&2
exit 1
fi
}
require_value BACKOFFICE_DB_USERNAME "$DB_USER"
require_value BACKOFFICE_DB_PASSWORD "$DB_PASSWORD"
require_value ADB_TNS "$DB_TNS"
TOKEN_HR="codex_hr_$(uuidgen)"
TOKEN_SELF="codex_self_$(uuidgen)"
TOKEN_ALL="codex_all_$(uuidgen)"
run_sqlcl() {
"$SQLCL_BIN" -s "$DB_USER/$DB_PASSWORD@$DB_TNS"
}
cleanup_tokens() {
{
printf "%s\n" "WHENEVER SQLERROR CONTINUE"
printf "%s\n" "UPDATE cb_agent_bearer_key SET revoked_at = SYSDATE, active = 'N' WHERE description = '$DESCRIPTION';"
printf "%s\n" "COMMIT;"
printf "%s\n" "exit"
} | run_sqlcl >/dev/null || true
}
trap cleanup_tokens EXIT
insert_tokens() {
{
printf "%s\n" "WHENEVER SQLERROR EXIT SQL.SQLCODE"
printf "%s\n" "INSERT INTO cb_agent_bearer_key(key_id, user_id, key_hash, key_prefix, expires_at, active, description) VALUES (cb_agent_bearer_key_seq.NEXTVAL, 101, STANDARD_HASH('$TOKEN_HR', 'SHA256'), 'reg_hr', SYSDATE + (10/1440), 'Y', '$DESCRIPTION');"
printf "%s\n" "INSERT INTO cb_agent_bearer_key(key_id, user_id, key_hash, key_prefix, expires_at, active, description) VALUES (cb_agent_bearer_key_seq.NEXTVAL, 102, STANDARD_HASH('$TOKEN_SELF', 'SHA256'), 'reg_self', SYSDATE + (10/1440), 'Y', '$DESCRIPTION');"
printf "%s\n" "INSERT INTO cb_agent_bearer_key(key_id, user_id, key_hash, key_prefix, expires_at, active, description) VALUES (cb_agent_bearer_key_seq.NEXTVAL, 103, STANDARD_HASH('$TOKEN_ALL', 'SHA256'), 'reg_all', SYSDATE + (10/1440), 'Y', '$DESCRIPTION');"
printf "%s\n" "COMMIT;"
printf "%s\n" "exit"
} | run_sqlcl >"$WORK_DIR/token-insert.out"
}
call_and_assert() {
local label="$1" token="$2" expected_count="$3" expected_ids="$4" expected_contents="$5"
local response_file="$WORK_DIR/${label}.response.json"
local request_file="$WORK_DIR/${label}.request.txt"
local url="${ORDS_BASE%/}/${ORDS_PATH}?limit=50"
{
printf "POST %s\n" "$url"
printf "Authorization: Bearer ****%s\n" "${token: -6}"
printf "Content-Type: application/json\n"
printf "{}\n"
} >"$request_file"
local status
status="$(curl -sS -o "$response_file" -w "%{http_code}" \
-X POST "$url" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d "{}")"
python3 - "$label" "$status" "$response_file" "$request_file" "$expected_count" "$expected_ids" "$expected_contents" <<'PY'
import json
import sys
label, status, response_file, request_file, expected_count, expected_ids, expected_contents = sys.argv[1:8]
if status != "200":
print(f"[FAIL] {label}: HTTP {status}")
print(f" request={request_file}")
print(f" response={response_file}")
raise SystemExit(1)
try:
with open(response_file, encoding="utf-8") as handle:
data = json.load(handle)
except Exception as exc:
print(f"[FAIL] {label}: JSON parse failed: {exc}")
print(f" request={request_file}")
print(f" response={response_file}")
raise SystemExit(1)
rows = data.get("items", data.get("rows", []))
ids = [row.get("DOC_ID", row.get("doc_id")) for row in rows]
contents_count = sum(1 for row in rows if "CONTENTS" in row or "contents" in row)
expected_ids_list = [int(value) for value in expected_ids.split(",") if value]
failures = []
if len(rows) != int(expected_count):
failures.append(f"rows expected {expected_count}, actual {len(rows)}")
if ids != expected_ids_list:
failures.append(f"ids expected {expected_ids_list}, actual {ids}")
if contents_count != int(expected_contents):
failures.append(f"rows_with_contents expected {expected_contents}, actual {contents_count}")
if failures:
print(f"[FAIL] {label}: " + "; ".join(failures))
print(f" request={request_file}")
print(f" response={response_file}")
raise SystemExit(1)
print(f"[PASS] {label}: rows={len(rows)} ids={ids} rows_with_contents={contents_count}")
PY
}
call_and_assert_rejected() {
local label="$1" token="$2"
local response_file="$WORK_DIR/${label}.response.json"
local request_file="$WORK_DIR/${label}.request.txt"
local url="${ORDS_BASE%/}/${ORDS_PATH}?limit=50"
{
printf "POST %s\n" "$url"
printf "Authorization: Bearer ****%s\n" "${token: -6}"
printf "Content-Type: application/json\n"
printf "{}\n"
} >"$request_file"
local status
status="$(curl -sS -o "$response_file" -w "%{http_code}" \
-X POST "$url" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d "{}")"
if [[ "$status" == "200" ]]; then
echo "[FAIL] $label: invalid token returned HTTP 200"
echo " request=$request_file"
echo " response=$response_file"
exit 1
fi
echo "[PASS] $label: rejected with HTTP $status"
}
echo "[INFO] SQLcl: $SQLCL_BIN"
echo "[INFO] ORDS: ${ORDS_BASE%/}/${ORDS_PATH}"
echo "[INFO] Evidence: $WORK_DIR"
insert_tokens
call_and_assert "HR" "$TOKEN_HR" "3" "1,2,6" "0"
call_and_assert "SELF" "$TOKEN_SELF" "1" "3" "0"
call_and_assert "ALL" "$TOKEN_ALL" "6" "1,2,3,4,5,6" "6"
call_and_assert_rejected "INVALID_TOKEN" "codex_invalid_$(uuidgen)"
echo "[PASS] VPD/Redaction ORDS regression passed"