mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
test(smoke): decouple admin checks from bootstrap credentials (#686)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
51ff9b99d2
commit
fc457a0651
8 changed files with 220 additions and 9 deletions
1
.github/workflows/pr-scripts.yml
vendored
1
.github/workflows/pr-scripts.yml
vendored
|
|
@ -38,5 +38,6 @@ jobs:
|
|||
- run: bash scripts/tests/runtime-secret-test.sh
|
||||
- run: bash scripts/tests/validate-release-config-test.sh
|
||||
- run: bash scripts/tests/nginx-forwarded-proto-test.sh
|
||||
- run: bash scripts/tests/smoke-test-admin-mode-test.sh
|
||||
- run: bash scripts/tests/dev-web-host-test.sh
|
||||
- run: bash scripts/tests/workflow-security-test.sh
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -313,7 +313,7 @@ staging: ## 构建并启动 staging 环境,运行 smoke test(混合模式:
|
|||
@echo "=== [4/5] Starting staging services ==="
|
||||
$(STAGING_COMPOSE) up -d --wait server web
|
||||
@echo "=== [5/5] Running smoke tests ==="
|
||||
@if BOOTSTRAP_ADMIN_USERNAME=admin BOOTSTRAP_ADMIN_PASSWORD='Admin@staging2026' \
|
||||
@if SMOKE_ADMIN_USERNAME=admin SMOKE_ADMIN_PASSWORD='Admin@staging2026' \
|
||||
bash scripts/smoke-test.sh $(STAGING_API_URL); then \
|
||||
echo ""; \
|
||||
echo "Staging passed. Environment is running:"; \
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -400,6 +400,18 @@ Run it against a local backend:
|
|||
./scripts/smoke-test.sh http://localhost:8080
|
||||
```
|
||||
|
||||
Admin label-management smoke checks run only when current admin credentials are
|
||||
supplied explicitly:
|
||||
|
||||
```bash
|
||||
SMOKE_ADMIN_USERNAME=admin SMOKE_ADMIN_PASSWORD='current-password' \
|
||||
./scripts/smoke-test.sh http://localhost:8080
|
||||
```
|
||||
|
||||
Use `SMOKE_ADMIN_CHECKS=false` for persistent environments where only non-admin
|
||||
smoke checks should run. The script no longer falls back to bootstrap admin
|
||||
password defaults.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
|
|
|
|||
10
README_zh.md
10
README_zh.md
|
|
@ -193,6 +193,16 @@ make generate-api # 重新生成 OpenAPI 类型
|
|||
./scripts/smoke-test.sh http://localhost:8080 # 运行冒烟测试
|
||||
```
|
||||
|
||||
管理员标签管理冒烟测试只会在显式提供当前管理员凭证时运行:
|
||||
|
||||
```bash
|
||||
SMOKE_ADMIN_USERNAME=admin SMOKE_ADMIN_PASSWORD='current-password' \
|
||||
./scripts/smoke-test.sh http://localhost:8080
|
||||
```
|
||||
|
||||
持久化环境只跑非管理员冒烟检查时,可设置 `SMOKE_ADMIN_CHECKS=false`。
|
||||
脚本不再回退使用 bootstrap 管理员默认密码。
|
||||
|
||||
说明:不要在 `server/` 下直接执行 `./mvnw -pl skillhub-app clean test`。`skillhub-app` 依赖同仓库的 sibling modules,单独 clean 构建时会回退到本地 Maven 仓库里的旧产物并出现大量 `cannot find symbol` / 签名不匹配错误。需要使用 `-am`,或者直接使用上面的 `make test-backend-app` / `make build-backend-app`。
|
||||
|
||||
### 项目结构
|
||||
|
|
|
|||
|
|
@ -129,6 +129,12 @@ This will:
|
|||
4. Run smoke tests against the API
|
||||
5. Print pass/fail summary
|
||||
|
||||
`scripts/smoke-test.sh` separates bootstrap creation from smoke credentials.
|
||||
Admin smoke checks run only when `SMOKE_ADMIN_USERNAME` and
|
||||
`SMOKE_ADMIN_PASSWORD` are provided. Use `SMOKE_ADMIN_CHECKS=false` when testing
|
||||
a persistent environment where the current admin password is not part of the
|
||||
smoke run.
|
||||
|
||||
If all tests pass, the environment stays running at:
|
||||
- Web UI: http://localhost
|
||||
- Backend API: http://localhost:8080
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ check() {
|
|||
fi
|
||||
}
|
||||
|
||||
finish() {
|
||||
echo
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
[[ "$FAIL" -eq 0 ]]
|
||||
}
|
||||
|
||||
echo "=== SkillHub Smoke Test ==="
|
||||
echo "Target: $BASE_URL"
|
||||
echo
|
||||
|
|
@ -113,8 +119,30 @@ else
|
|||
fi
|
||||
|
||||
# ---- Label Management (requires admin) ----
|
||||
ADMIN_USERNAME="${BOOTSTRAP_ADMIN_USERNAME:-admin}"
|
||||
ADMIN_PASSWORD="${BOOTSTRAP_ADMIN_PASSWORD:-ChangeMe!2026}"
|
||||
SMOKE_ADMIN_CHECKS="${SMOKE_ADMIN_CHECKS:-auto}"
|
||||
SMOKE_ADMIN_USERNAME="${SMOKE_ADMIN_USERNAME:-}"
|
||||
SMOKE_ADMIN_PASSWORD="${SMOKE_ADMIN_PASSWORD:-}"
|
||||
ADMIN_CONFIG_FAILED=0
|
||||
if [[ "$SMOKE_ADMIN_CHECKS" != "auto" && "$SMOKE_ADMIN_CHECKS" != "true" && "$SMOKE_ADMIN_CHECKS" != "false" ]]; then
|
||||
echo "FAIL: SMOKE_ADMIN_CHECKS must be auto, true, or false"
|
||||
FAIL=$((FAIL + 1))
|
||||
ADMIN_CONFIG_FAILED=1
|
||||
fi
|
||||
if [[ "$SMOKE_ADMIN_CHECKS" == "true" && ( -z "$SMOKE_ADMIN_USERNAME" || -z "$SMOKE_ADMIN_PASSWORD" ) ]]; then
|
||||
echo "FAIL: SMOKE_ADMIN_CHECKS=true requires SMOKE_ADMIN_USERNAME and SMOKE_ADMIN_PASSWORD"
|
||||
FAIL=$((FAIL + 1))
|
||||
ADMIN_CONFIG_FAILED=1
|
||||
fi
|
||||
if [[ "$ADMIN_CONFIG_FAILED" -ne 0 ]]; then
|
||||
finish
|
||||
exit $?
|
||||
fi
|
||||
if [[ "$SMOKE_ADMIN_CHECKS" == "false" || ( "$SMOKE_ADMIN_CHECKS" == "auto" && ( -z "$SMOKE_ADMIN_USERNAME" || -z "$SMOKE_ADMIN_PASSWORD" ) ) ]]; then
|
||||
echo "SKIP: Admin label management (set SMOKE_ADMIN_USERNAME and SMOKE_ADMIN_PASSWORD to enable)"
|
||||
finish
|
||||
exit $?
|
||||
fi
|
||||
|
||||
ADMIN_COOKIE_JAR="$(mktemp)"
|
||||
LABEL_SLUG="smoke-label-$(date +%s)"
|
||||
|
||||
|
|
@ -134,7 +162,7 @@ ADMIN_LOGIN_STATUS="$(curl --max-time 10 -s -o /dev/null -w "%{http_code}" \
|
|||
-c "$ADMIN_COOKIE_JAR" \
|
||||
-H "X-XSRF-TOKEN: $ADMIN_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"$ADMIN_USERNAME\",\"password\":\"$ADMIN_PASSWORD\"}" || true)"
|
||||
-d "{\"username\":\"$SMOKE_ADMIN_USERNAME\",\"password\":\"$SMOKE_ADMIN_PASSWORD\"}" || true)"
|
||||
if [[ "$ADMIN_LOGIN_STATUS" == "200" ]]; then
|
||||
echo "PASS: Admin login (HTTP $ADMIN_LOGIN_STATUS)"
|
||||
PASS=$((PASS + 1))
|
||||
|
|
@ -196,8 +224,4 @@ else
|
|||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
if [[ "$FAIL" -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
finish
|
||||
|
|
|
|||
156
scripts/tests/smoke-test-admin-mode-test.sh
Executable file
156
scripts/tests/smoke-test-admin-mode-test.sh
Executable file
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
SMOKE_SCRIPT="$REPO_ROOT/scripts/smoke-test.sh"
|
||||
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf "$TMP_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$TMP_DIR/bin"
|
||||
cat >"$TMP_DIR/bin/curl" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
url=""
|
||||
method="GET"
|
||||
data=""
|
||||
cookie_in=""
|
||||
cookie_out=""
|
||||
write_code=false
|
||||
output_file=""
|
||||
while (($#)); do
|
||||
case "$1" in
|
||||
-X)
|
||||
method="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d)
|
||||
data="$2"
|
||||
shift 2
|
||||
;;
|
||||
-b)
|
||||
cookie_in="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c)
|
||||
cookie_out="$2"
|
||||
shift 2
|
||||
;;
|
||||
-w)
|
||||
write_code=true
|
||||
shift 2
|
||||
;;
|
||||
-o)
|
||||
output_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
-H|--max-time|--retry|--retry-delay)
|
||||
shift 2
|
||||
;;
|
||||
-s|-sS)
|
||||
shift
|
||||
;;
|
||||
http://*|https://*)
|
||||
url="$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -n "$cookie_out" ]]; then
|
||||
printf '%s\n' "localhost FALSE / FALSE 0 XSRF-TOKEN csrf-token" >>"$cookie_out"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$method $url $data" >>"${SMOKE_CURL_LOG:?SMOKE_CURL_LOG is required}"
|
||||
|
||||
status=200
|
||||
case "$url" in
|
||||
*/actuator/health) status=200 ;;
|
||||
*/actuator/prometheus) status=401 ;;
|
||||
*/api/v1/namespaces)
|
||||
if [[ -n "$cookie_in" && -f "$cookie_in.session" ]]; then status=200; else status=401; fi
|
||||
;;
|
||||
*/api/v1/auth/me)
|
||||
if [[ -n "$cookie_in" && -f "$cookie_in.session" && ! -f "$cookie_in.logged-out" ]]; then status=200; else status=401; fi
|
||||
;;
|
||||
*/api/v1/auth/local/register)
|
||||
[[ -n "$cookie_out" ]] && touch "$cookie_out.session"
|
||||
status=200
|
||||
;;
|
||||
*/api/v1/auth/local/change-password) status=200 ;;
|
||||
*/api/v1/auth/logout)
|
||||
[[ -n "$cookie_out" ]] && touch "$cookie_out.logged-out"
|
||||
status=200
|
||||
;;
|
||||
*/api/v1/auth/local/login)
|
||||
if [[ "$data" == *'"username":"current-admin"'* && "$data" == *'"password":"current-secret"'* ]]; then
|
||||
[[ -n "$cookie_out" ]] && touch "$cookie_out.session"
|
||||
status=200
|
||||
else
|
||||
status=401
|
||||
fi
|
||||
;;
|
||||
*/api/v1/admin/labels|*/api/v1/labels|*/api/v1/admin/labels/*)
|
||||
status=200
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$output_file" != "/dev/null" && -n "$output_file" ]]; then
|
||||
printf '{}\n' >"$output_file"
|
||||
fi
|
||||
if [[ "$write_code" == true ]]; then
|
||||
printf '%s' "$status"
|
||||
fi
|
||||
EOF
|
||||
chmod +x "$TMP_DIR/bin/curl"
|
||||
|
||||
run_smoke() {
|
||||
local name="$1"
|
||||
shift
|
||||
local log="$TMP_DIR/$name.curl.log"
|
||||
local out="$TMP_DIR/$name.out"
|
||||
local status=0
|
||||
env PATH="$TMP_DIR/bin:$PATH" SMOKE_CURL_LOG="$log" "$@" "$SMOKE_SCRIPT" http://skillhub.test >"$out" 2>&1 || status=$?
|
||||
printf '%s\n' "$status"
|
||||
}
|
||||
|
||||
status="$(run_smoke skip-admin env)"
|
||||
[[ "$status" == "0" ]] || fail "default smoke without admin credentials should pass"
|
||||
grep -Fq "SKIP: Admin label management" "$TMP_DIR/skip-admin.out" \
|
||||
|| fail "default smoke should skip admin section without explicit credentials"
|
||||
if grep -Fq "/api/v1/auth/local/login" "$TMP_DIR/skip-admin.curl.log"; then
|
||||
fail "default smoke must not attempt admin login without explicit credentials"
|
||||
fi
|
||||
|
||||
status="$(run_smoke missing-admin env SMOKE_ADMIN_CHECKS=true)"
|
||||
[[ "$status" != "0" ]] || fail "SMOKE_ADMIN_CHECKS=true without credentials should fail"
|
||||
grep -Fq "SMOKE_ADMIN_CHECKS=true requires SMOKE_ADMIN_USERNAME and SMOKE_ADMIN_PASSWORD" "$TMP_DIR/missing-admin.out" \
|
||||
|| fail "missing admin credentials should produce an actionable error"
|
||||
if grep -Fq "/api/v1/auth/local/login" "$TMP_DIR/missing-admin.curl.log"; then
|
||||
fail "missing explicit admin credentials must stop before admin login"
|
||||
fi
|
||||
|
||||
status="$(run_smoke explicit-admin env SMOKE_ADMIN_USERNAME=current-admin SMOKE_ADMIN_PASSWORD=current-secret BOOTSTRAP_ADMIN_PASSWORD=wrong-bootstrap)"
|
||||
[[ "$status" == "0" ]] || fail "explicit admin credentials should run full smoke successfully"
|
||||
grep -Fq '"username":"current-admin","password":"current-secret"' "$TMP_DIR/explicit-admin.curl.log" \
|
||||
|| fail "admin login should use SMOKE_ADMIN credentials"
|
||||
if grep -Fq 'wrong-bootstrap' "$TMP_DIR/explicit-admin.curl.log"; then
|
||||
fail "admin login must not use BOOTSTRAP_ADMIN_PASSWORD"
|
||||
fi
|
||||
if grep -Fq 'ChangeMe!2026' "$TMP_DIR/explicit-admin.curl.log"; then
|
||||
fail "admin login must not fall back to the bootstrap default password"
|
||||
fi
|
||||
|
||||
echo "smoke-test-admin-mode-test passed"
|
||||
|
|
@ -77,6 +77,8 @@ grep -Fq 'bash scripts/tests/validate-release-config-test.sh' "$PR_SCRIPTS_WORKF
|
|||
|| fail "pr-scripts must run validate-release-config-test"
|
||||
grep -Fq 'bash scripts/tests/nginx-forwarded-proto-test.sh' "$PR_SCRIPTS_WORKFLOW" \
|
||||
|| fail "pr-scripts must run nginx-forwarded-proto-test"
|
||||
grep -Fq 'bash scripts/tests/smoke-test-admin-mode-test.sh' "$PR_SCRIPTS_WORKFLOW" \
|
||||
|| fail "pr-scripts must run smoke-test-admin-mode-test"
|
||||
grep -Fq 'bash scripts/tests/runtime-secret-test.sh' "$PR_SCRIPTS_WORKFLOW" \
|
||||
|| fail "pr-scripts must run runtime-secret-test"
|
||||
grep -Fq 'bash scripts/tests/dev-web-host-test.sh' "$PR_SCRIPTS_WORKFLOW" \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue