181 lines
6.2 KiB
Bash
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"
|