diff --git a/docs/design/460-sqlcl-runbook-env-check/README.md b/docs/design/460-sqlcl-runbook-env-check/README.md new file mode 100644 index 0000000..d5edcda --- /dev/null +++ b/docs/design/460-sqlcl-runbook-env-check/README.md @@ -0,0 +1,82 @@ +# 설계서: SQLcl 기반 배포/롤백 런북 및 환경 점검 명령 정리 (#460) + +> **상태**: Approved +> **작성**: [AI] Architect · **최종수정**: 2026-06-25 +> **추적성** — Redmine: #460 · 관련 ADR: 없음 +> · 구현 파일: `scripts/check-sqlcl-backoffice-env.sh`, `docs/runbooks/460-sqlcl-vpd-deploy-runbook.md`, `run.sh` · 테스트: `./run.sh backoffice-env-check` + +## 1. 목적 (Why) + +운영자가 신규 DB/ORDS 환경에서 SQLcl, JDK, ADB 접속, ORDS endpoint를 적용 전에 점검하고 VPD filter 배포/검증/롤백 순서를 확인할 수 있게 한다. + +## 2. 범위 (Scope) + +- **포함**: SQLcl/JDK/DB/ORDS 환경 점검 스크립트, 배포/검증/롤백 런북, `run.sh backoffice-env-check` 명령. +- **제외**: SQLcl 설치 자동화, JDK 설치 자동화, ORDS metadata 자동 생성. + +## 3. 인수조건 (Acceptance Criteria) + +- [ ] SQLcl 실행 파일과 버전을 확인한다. +- [ ] Java 버전을 확인한다. +- [ ] DB 접속 사용자와 `CB_AGENT_DOC_VPD_FILTER` 상태를 확인한다. +- [ ] ORDS base URL과 documents endpoint의 HTTP 상태를 확인한다. +- [ ] 운영자가 실행할 배포/검증/롤백 순서가 문서화된다. + +## 4. 컨텍스트 & 제약 + +- `.env`는 민감 정보를 포함하므로 점검 출력에 password/token을 출력하지 않는다. +- SQLcl 경로는 `SQLCL_BIN` 우선, 없으면 PATH의 `sql`을 사용한다. +- JDK는 `SQLCL_JAVA_HOME`이 있으면 `JAVA_HOME`으로 사용한다. + +## 5. 아키텍처 개요 + +``` +run.sh backoffice-env-check + -> scripts/check-sqlcl-backoffice-env.sh + -> SQLcl version + -> Java version + -> SELECT USER, function status + -> curl ORDS endpoint +``` + +## 6. 데이터 모델 + +- 입력 환경변수: `SQLCL_BIN`, `SQLCL_JAVA_HOME`, `BACKOFFICE_DB_USERNAME`, `BACKOFFICE_DB_PASSWORD`, `ADB_TNS`, `BACKOFFICE_ORDS_BASE_URL`. +- 출력: PASS/FAIL 로그, 민감값 마스킹. + +## 7. 함수 명세 (Function Specs) + +| 함수 | 책임(1줄) | 시그니처(잠정) | 입력 | 출력 | 에러/실패 | 복잡? | +|------|-----------|----------------|------|------|-----------|-------| +| `resolve_sqlcl` | SQLcl 실행 파일 찾기 | bash function | env/path | path | 없으면 exit 1 | 단순 | +| `check_db` | DB 접속과 function 상태 확인 | bash function | SQLcl connection | PASS/FAIL | SQLcl exit code | 단순 | +| `check_ords` | ORDS endpoint HTTP 상태 확인 | bash function | base url/path | PASS/WARN | curl status | 단순 | + +## 8. 흐름 / 알고리즘 + +1. `.env`를 로드한다. +2. SQLcl 경로와 Java 버전을 출력한다. +3. DB 접속 필수값 존재 여부를 확인한다. +4. SQLcl로 현재 사용자와 VPD function 상태를 조회한다. +5. ORDS endpoint에 GET을 보내 상태 코드를 확인한다. +6. 다음 실행 명령을 안내한다. + +## 9. 엣지케이스 & 에러 처리 + +- SQLcl 없음: `SQLCL_BIN=/path/to/sql` 안내. +- DB 접속 실패: DB 설정 확인 메시지. +- ORDS 404: base URL/path 확인 경고. +- ORDS 401/403: endpoint는 살아 있으나 인증 필요 상태로 안내. + +## 10. 테스트 계획 + +- `SQLCL_BIN=/tmp/sqlcl/sqlcl/bin/sql SQLCL_JAVA_HOME=... ./run.sh backoffice-env-check` + +## 11. 리스크 & 대안 검토 + +- 선택: bash 점검 스크립트. 운영자가 Java/Maven 없이도 SQLcl/curl만으로 확인 가능하다. +- 대안: Spring Boot health endpoint. 앱이 뜨기 전 문제를 잡기 어렵다. + +## 12. 미해결 질문 (Open Questions) + +- SQLcl을 repo 외부 어디에 표준 설치할지는 사용자 로컬/운영 환경 정책에 따른다. diff --git a/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md b/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md new file mode 100644 index 0000000..9cea05f --- /dev/null +++ b/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md @@ -0,0 +1,78 @@ +# SQLcl VPD 배포/검증/롤백 런북 (#460) + +## 사전 점검 + +```bash +SQLCL_BIN=/path/to/sql \ +SQLCL_JAVA_HOME=/path/to/jdk \ +./run.sh backoffice-env-check +``` + +확인 항목: + +- SQLcl 버전이 출력된다. +- Java 11 이상이 출력된다. +- DB 현재 사용자가 의도한 schema다. 예: `ADMIN`. +- `CB_AGENT_DOC_VPD_FILTER` 상태가 `VALID`다. +- ORDS endpoint가 200/401/403 중 하나를 반환한다. 404면 base URL 또는 path가 맞지 않는다. + +## VPD filter 배포 + +```bash +SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@TNS" +``` + +SQLcl 안에서 실행: + +```sql +@sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql +SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter +@sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql +``` + +기대 결과: + +- function compile 성공 +- `SHOW ERRORS` 결과 없음 +- `Dynamic VPD filter unit checks passed` + +## ORDS 회귀 검증 + +```bash +SQLCL_BIN=/path/to/sql \ +SQLCL_JAVA_HOME=/path/to/jdk \ +./run.sh backoffice-vpd-ords-test +``` + +기대 결과: + +- HR: 3행, `DOC_ID=[1,2,6]`, `CONTENTS` 미노출 +- SELF: 1행, `DOC_ID=[3]`, `CONTENTS` 미노출 +- ALL: 6행, `DOC_ID=[1,2,3,4,5,6]`, `CONTENTS` 노출 +- INVALID_TOKEN: HTTP 403 등 성공이 아닌 응답 + +## 장애 시 확인 순서 + +1. `./run.sh backoffice-env-check`로 SQLcl/JDK/DB/ORDS 상태를 먼저 확인한다. +2. DB function이 `INVALID`면 `SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter`를 본다. +3. ORDS가 404면 `BACKOFFICE_ORDS_BASE_URL`과 `cb_protected_object.ords_path`를 비교한다. +4. ORDS가 403이면 token hash, 만료시각, revoke 여부를 확인한다. +5. 행 수가 맞지 않으면 `cb_user_role`, `cb_permission`, `cb_permission_rule`을 확인한다. + +## 롤백 + +가장 단순한 롤백은 직전 Git revision의 `26_agent_ords_security_dynamic_vpd_filter.sql`을 다시 적용하는 것이다. + +```bash +git show HEAD~1:sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql > /tmp/previous-vpd-filter.sql +SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@TNS" +``` + +SQLcl 안에서: + +```sql +@/tmp/previous-vpd-filter.sql +SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter +``` + +롤백 후에도 반드시 ORDS 회귀 검증을 다시 실행한다. diff --git a/run.sh b/run.sh index 9d0dd91..f7a3d2b 100755 --- a/run.sh +++ b/run.sh @@ -10,6 +10,7 @@ # ./run.sh tests # 4-user (my/pg/both/none) 로 접속해서 행 필터 검증 # ./run.sh audit # admin 으로 정책/뷰/유저 상태 점검 # ./run.sh backoffice-support # Spring Boot 백오피스 보조 객체 생성 +# ./run.sh backoffice-env-check # SQLcl/JDK/DB/ORDS 환경 점검 # ./run.sh backoffice-vpd-ords-test # SQLcl + ORDS VPD/Redaction 회귀 테스트 # ./run.sh all # source → adb → tests → audit # ./run.sh teardown # ADB 측 객체 + 원격 link/cred 만 정리 (원격 PG/MySQL 데이터는 보존) @@ -181,6 +182,12 @@ do_backoffice_vpd_ords_test() { ok "backoffice-vpd-ords-test 완료" } +do_backoffice_env_check() { + log "=== backoffice-env-check: SQLcl/JDK/DB/ORDS 환경 점검 ===" + bash "$ROOT/scripts/check-sqlcl-backoffice-env.sh" + ok "backoffice-env-check 완료" +} + do_teardown() { log "=== teardown: ADB 측 객체 + dblink/credential 정리 ===" warn "원격 PG/MySQL 의 customers 테이블은 건드리지 않습니다 (수동으로 DROP 하세요)" @@ -233,6 +240,7 @@ case "$CMD" in tests) do_prereq; do_tests ;; audit) do_prereq; do_audit ;; backoffice-support) do_prereq; do_backoffice_support ;; + backoffice-env-check) do_backoffice_env_check ;; backoffice-vpd-ords-test) do_backoffice_vpd_ords_test ;; teardown) do_prereq; do_teardown ;; all) @@ -253,6 +261,6 @@ case "$CMD" in ok "=== DDS DONE — Deep Data Security 변형 셋업 + 검증 통과 ===" ;; *) - die "알 수 없는 명령: $CMD (사용: prereq|source|adb|tests|audit|backoffice-support|backoffice-vpd-ords-test|all|teardown | dds|dds-setup|dds-tests|dds-teardown)" + die "알 수 없는 명령: $CMD (사용: prereq|source|adb|tests|audit|backoffice-support|backoffice-env-check|backoffice-vpd-ords-test|all|teardown | dds|dds-setup|dds-tests|dds-teardown)" ;; esac diff --git a/scripts/check-sqlcl-backoffice-env.sh b/scripts/check-sqlcl-backoffice-env.sh new file mode 100644 index 0000000..155eab8 --- /dev/null +++ b/scripts/check-sqlcl-backoffice-env.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# Check SQLcl/JDK/ADB/ORDS prerequisites for the VPD backoffice scripts. +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 [[ -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}" + +fail() { + echo "[FAIL] $*" >&2 + exit 1 +} + +warn() { + echo "[WARN] $*" >&2 +} + +pass() { + echo "[PASS] $*" +} + +[[ -n "$SQLCL_BIN" && -x "$SQLCL_BIN" ]] || fail "SQLcl을 찾을 수 없습니다. SQLCL_BIN=/path/to/sql 로 지정하세요." +[[ -n "$DB_USER" ]] || fail "BACKOFFICE_DB_USERNAME 또는 ADB_USER가 필요합니다." +[[ -n "$DB_PASSWORD" ]] || fail "BACKOFFICE_DB_PASSWORD 또는 ADB_PASSWORD가 필요합니다." +[[ -n "$DB_TNS" ]] || fail "ADB_TNS가 필요합니다." + +echo "[INFO] SQLcl path: $SQLCL_BIN" +"$SQLCL_BIN" -version + +if command -v java >/dev/null 2>&1; then + java -version 2>&1 | sed -n '1,3p' +else + warn "java 명령을 PATH에서 찾을 수 없습니다. SQLcl이 자체 Java를 쓰지 않는 환경이면 실패할 수 있습니다." +fi + +echo "[INFO] DB user: $DB_USER" +{ + printf "%s\n" "WHENEVER SQLERROR EXIT SQL.SQLCODE" + printf "%s\n" "SET SQLFORMAT ansiconsole" + printf "%s\n" "SELECT USER AS current_user FROM dual;" + printf "%s\n" "SELECT object_name, status FROM user_objects WHERE object_name = 'CB_AGENT_DOC_VPD_FILTER';" + printf "%s\n" "exit" +} | "$SQLCL_BIN" -s "$DB_USER/$DB_PASSWORD@$DB_TNS" +pass "DB 접속 및 VPD function 상태 조회 완료" + +ORDS_URL="${ORDS_BASE%/}/${ORDS_PATH}?limit=1" +STATUS="$(curl -sS -o /tmp/vpd-backoffice-env-check-ords.json -w "%{http_code}" \ + -X POST "$ORDS_URL" \ + -H "Content-Type: application/json" \ + -d "{}" || true)" +case "$STATUS" in + 200|401|403) + pass "ORDS endpoint 응답 확인: HTTP $STATUS" + ;; + 404) + warn "ORDS endpoint가 404입니다. BACKOFFICE_ORDS_BASE_URL과 ORDS path를 확인하세요: $ORDS_URL" + ;; + *) + warn "ORDS endpoint 응답이 예상 밖입니다: HTTP $STATUS ($ORDS_URL)" + ;; +esac + +echo "[INFO] 다음 검증: ./run.sh backoffice-vpd-ords-test"