mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
feat: add API key bearer token authentication
- ApiKeyVerifier(TokenVerifier) — validates Authorization: Bearer <key> against UNRAID_MCP_API_KEY; guards against empty-key bypass - _build_auth() replaces module-level _build_google_auth() call: returns MultiAuth(server=google, verifiers=[api_key]) when both set, GoogleProvider alone, ApiKeyVerifier alone, or None - settings.py: add UNRAID_MCP_API_KEY + is_api_key_auth_configured() + api_key_auth_enabled in get_config_summary() - run_server(): improved auth status logging for all three states - tests/test_api_key_auth.py: 9 tests covering verifier + _build_auth - .env.example: add UNRAID_MCP_API_KEY section - docs/GOOGLE_OAUTH.md: add API Key section - README.md / CLAUDE.md: rename section, document both auth methods - Fix pre-existing: test_health.py patched cache_middleware/error_middleware now match renamed _cache_middleware/_error_middleware in server.py
This commit is contained in:
@@ -134,6 +134,11 @@ check_prerequisites() {
|
||||
missing=true
|
||||
fi
|
||||
|
||||
if ! command -v jq &>/dev/null; then
|
||||
log_error "jq not found in PATH. Install it and re-run."
|
||||
missing=true
|
||||
fi
|
||||
|
||||
if [[ ! -f "${PROJECT_DIR}/pyproject.toml" ]]; then
|
||||
log_error "pyproject.toml not found at ${PROJECT_DIR}. Wrong directory?"
|
||||
missing=true
|
||||
@@ -181,10 +186,12 @@ smoke_test_server() {
|
||||
import sys, json
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
if 'status' in d or 'success' in d or 'error' in d:
|
||||
if 'error' in d:
|
||||
print('error: tool returned error key — ' + str(d.get('error', '')))
|
||||
elif 'status' in d or 'success' in d:
|
||||
print('ok')
|
||||
else:
|
||||
print('missing: no status/success/error key in response')
|
||||
print('missing: no status/success key in response')
|
||||
except Exception as e:
|
||||
print('parse_error: ' + str(e))
|
||||
" 2>/dev/null
|
||||
@@ -253,6 +260,31 @@ run_test() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Always validate JSON is parseable and not an error payload
|
||||
local json_check
|
||||
json_check="$(
|
||||
printf '%s' "${output}" | python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
if isinstance(d, dict) and ('error' in d or d.get('kind') == 'error'):
|
||||
print('error: ' + str(d.get('error', d.get('message', 'unknown error'))))
|
||||
else:
|
||||
print('ok')
|
||||
except Exception as e:
|
||||
print('invalid_json: ' + str(e))
|
||||
" 2>/dev/null
|
||||
)" || json_check="parse_error"
|
||||
|
||||
if [[ "${json_check}" != "ok" ]]; then
|
||||
printf "${C_RED}[FAIL]${C_RESET} %-55s ${C_DIM}%dms${C_RESET}\n" \
|
||||
"${label}" "${elapsed_ms}" | tee -a "${LOG_FILE}"
|
||||
printf ' response validation failed: %s\n' "${json_check}" | tee -a "${LOG_FILE}"
|
||||
FAIL_COUNT=$(( FAIL_COUNT + 1 ))
|
||||
FAIL_NAMES+=("${label}")
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate optional key presence
|
||||
if [[ -n "${expected_key}" ]]; then
|
||||
local key_check
|
||||
|
||||
Reference in New Issue
Block a user