test(release): verify Android production routes read-only
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
SCRIPT="$ROOT_DIR/scripts/verify-aug1-production-api-readonly.sh"
|
||||
DEV_SETUP="$ROOT_DIR/docs/DEV_SETUP.md"
|
||||
AUTH_CONTROLLER="$ROOT_DIR/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java"
|
||||
MOBILE_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java"
|
||||
KNOWLEDGE_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/knowledge/controller/AihrKnowledgeQueryController.java"
|
||||
SOP_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSopController.java"
|
||||
PRACTICE_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java"
|
||||
AGENT_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentController.java"
|
||||
DIRECT_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/direct/AihrDirectController.java"
|
||||
SPEECH_CONTROLLER="$ROOT_DIR/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrSpeechController.java"
|
||||
|
||||
bash -n "$SCRIPT"
|
||||
|
||||
probe_count="$(grep -Ec '^(public|auth|method)_[^|]+\|/[^|]+\|[0-9]+$' "$SCRIPT")"
|
||||
[[ "$probe_count" -eq 20 ]]
|
||||
[[ "$(grep -Ec '^public_[^|]+\|/[^|]+\|200$' "$SCRIPT")" -eq 1 ]]
|
||||
[[ "$(grep -Ec '^auth_[^|]+\|/[^|]+\|401$' "$SCRIPT")" -eq 6 ]]
|
||||
[[ "$(grep -Ec '^method_[^|]+\|/[^|]+\|405$' "$SCRIPT")" -eq 13 ]]
|
||||
|
||||
grep -Fq 'side_effects=GET-only' "$SCRIPT"
|
||||
grep -Fq 'sms-code endpoint intentionally excluded' "$SCRIPT"
|
||||
grep -Fq './scripts/verify-aug1-production-api-readonly.sh' "$DEV_SETUP"
|
||||
|
||||
grep -Fq '@PostMapping("/mobile/sms-login")' "$AUTH_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/home/{role}")' "$MOBILE_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/me")' "$MOBILE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/query")' "$KNOWLEDGE_CONTROLLER"
|
||||
grep -Fq '@PostMapping(value = "/query-media"' "$KNOWLEDGE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/resources/{attachmentId}/download-link")' "$KNOWLEDGE_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/position-sop")' "$SOP_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/answer-feedback")' "$SOP_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/answer-feedback")' "$SOP_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/summary-card")' "$SOP_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/scenarios")' "$PRACTICE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/start")' "$PRACTICE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/turn")' "$PRACTICE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/finish")' "$PRACTICE_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/messages")' "$AGENT_CONTROLLER"
|
||||
grep -Fq '@PostMapping(value = "/messages/media"' "$AGENT_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/channels")' "$DIRECT_CONTROLLER"
|
||||
grep -Fq '@GetMapping("/mine")' "$DIRECT_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/feedback")' "$DIRECT_CONTROLLER"
|
||||
grep -Fq '@PostMapping(value = "/asr"' "$SPEECH_CONTROLLER"
|
||||
grep -Fq '@PostMapping("/tts")' "$SPEECH_CONTROLLER"
|
||||
|
||||
for forbidden in \
|
||||
'curl -X' \
|
||||
'--request' \
|
||||
'--data' \
|
||||
'--form' \
|
||||
'phonenumber=' \
|
||||
'Authorization:' \
|
||||
'/resource/sms/code'; do
|
||||
if grep -Fq -- "$forbidden" "$SCRIPT"; then
|
||||
echo "FAIL: read-only production API verifier contains forbidden request material: $forbidden" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'PASS: August 1 production API verifier is GET-only and excludes SMS/login side effects'
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
base_url="${AUG1_PRODUCTION_API_URL:-https://peilian.njzhmj.top/prod-api}"
|
||||
base_url="${base_url%/}"
|
||||
[[ "$base_url" =~ ^https://[A-Za-z0-9.-]+(:[0-9]+)?(/[^[:space:]]*)?$ ]] || {
|
||||
echo "verify-aug1-production-api-readonly: AUG1_PRODUCTION_API_URL must be an HTTPS URL" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
read -r -d '' probes <<'PROBES' || true
|
||||
public_mobile_home|/api/aihr/mobile/home/user|200
|
||||
auth_mobile_me|/api/aihr/mobile/me|401
|
||||
auth_position_sop|/api/knowledge/position-sop|401
|
||||
auth_practice_scenarios|/api/train/practice/scenarios|401
|
||||
auth_direct_channels|/api/aihr/direct/channels|401
|
||||
auth_direct_mine|/api/aihr/direct/mine?pageNum=1&pageSize=1|401
|
||||
method_sms_login|/auth/mobile/sms-login|405
|
||||
method_knowledge_query|/api/knowledge/query|405
|
||||
method_knowledge_media|/api/knowledge/query-media|405
|
||||
method_resource_download_link|/api/knowledge/resources/0/download-link|405
|
||||
auth_answer_feedback|/api/knowledge/answer-feedback|401
|
||||
method_summary_card|/api/knowledge/summary-card|405
|
||||
method_practice_start|/api/train/practice/start|405
|
||||
method_practice_turn|/api/train/practice/turn|405
|
||||
method_practice_finish|/api/train/practice/finish|405
|
||||
method_agent_messages|/api/aihr/agent/messages|405
|
||||
method_agent_media|/api/aihr/agent/messages/media|405
|
||||
method_direct_feedback|/api/aihr/direct/feedback|405
|
||||
method_asr|/api/ai/asr|405
|
||||
method_tts|/api/ai/tts|405
|
||||
PROBES
|
||||
|
||||
total=0
|
||||
public_count=0
|
||||
auth_count=0
|
||||
method_count=0
|
||||
|
||||
while IFS='|' read -r label path expected_code; do
|
||||
[[ -n "$label" ]] || continue
|
||||
response="$(
|
||||
curl -sS --max-time 15 \
|
||||
-H 'Accept: application/json' \
|
||||
-w $'\n__AUG1_HTTP__%{http_code}' \
|
||||
"$base_url$path"
|
||||
)" || {
|
||||
echo "verify-aug1-production-api-readonly: GET failed for $label $path" >&2
|
||||
exit 1
|
||||
}
|
||||
http_line="${response##*$'\n'__AUG1_HTTP__}"
|
||||
body="${response%$'\n'__AUG1_HTTP__*}"
|
||||
[[ "$http_line" == "200" ]] || {
|
||||
echo "verify-aug1-production-api-readonly: $label expected HTTP 200, got $http_line" >&2
|
||||
exit 1
|
||||
}
|
||||
business_code="$(
|
||||
printf '%s' "$body" |
|
||||
sed -nE 's/^[[:space:]]*\{[[:space:]]*"code"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p'
|
||||
)"
|
||||
[[ "$business_code" == "$expected_code" ]] || {
|
||||
echo "verify-aug1-production-api-readonly: $label expected business code $expected_code, got ${business_code:-missing}" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "$label=HTTP/200 business/$business_code GET $path"
|
||||
total=$((total + 1))
|
||||
case "$expected_code" in
|
||||
200) public_count=$((public_count + 1)) ;;
|
||||
401) auth_count=$((auth_count + 1)) ;;
|
||||
405) method_count=$((method_count + 1)) ;;
|
||||
*)
|
||||
echo "verify-aug1-production-api-readonly: unsupported expected code $expected_code" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done <<<"$probes"
|
||||
|
||||
[[ "$total" -eq 20 ]] || {
|
||||
echo "verify-aug1-production-api-readonly: expected 20 probes, ran $total" >&2
|
||||
exit 1
|
||||
}
|
||||
[[ "$public_count" -eq 1 && "$auth_count" -eq 6 && "$method_count" -eq 13 ]] || {
|
||||
echo "verify-aug1-production-api-readonly: unexpected probe distribution $public_count/$auth_count/$method_count" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "aug1_production_api_readonly=passed total=$total public=$public_count auth_closed=$auth_count method_closed=$method_count"
|
||||
echo "side_effects=GET-only; sms-code endpoint intentionally excluded; no login, token, upload or business POST"
|
||||
Reference in New Issue
Block a user