Files
ss-tools/scripts/check_llm_certs.sh
busya 2cc2896740 fix: rewrite check_llm_certs.sh — tests all methods AI needs
Tests 4 variants: openssl s_client (CAfile, CApath, default),
Python httpx (cafile, cafile+capath), requests (cafile, capath),
NSS certutil. Output format is machine-parseable for AI diagnosis.
2026-05-28 22:56:19 +03:00

158 lines
6.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# #region check_llm_certs [C:4] [TYPE Module] [SEMANTICS ssl, certs, diagnostics, openssl, nss]
# @BRIEF Diagnóstico SSL pro ss-tools. Testuje všechny vrstvy: OpenSSL,
# Python httpx (jako LLMClient), Python requests (jako translate),
# NSS Chromium (jako Playwright). Výstup použije AI k opravě kódu.
# @USAGE ./scripts/check_llm_certs.sh [--target https://...] [-v]
# @LAYER Infrastructure
# @EXAMPLE:
# ./scripts/check_llm_certs.sh --target https://lite.ai.rusal.com
# #endregion check_llm_certs
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
PASS="${GREEN}${NC}"; FAIL="${RED}${NC}"; WARN="${YELLOW}${NC}"; INFO="${CYAN}${NC}"
TARGET_URL="${1:-https://lite.ai.rusal.com}"
HOST="$(echo "$TARGET_URL" | sed 's|https://||;s|/.*$||')"
CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
CA_DIR="/etc/ssl/certs"
NSS_DB="sql:${HOME:-/root}/.pki/nssdb"
echo -e "${CYAN}╔════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ LLM SSL Certificate Diagnostic Report ║${NC}"
echo -e "${CYAN}║ Target: ${TARGET_URL}${NC}"
echo -e "${CYAN}╚════════════════════════════════════════════════════╝${NC}"
echo ""
# ──────────────────────────────────────────────
# 1. SYSTEM CA STORE
# ──────────────────────────────────────────────
echo -e "${CYAN}── 1. System CA Store ──${NC}"
echo "ca_bundle=${CA_BUNDLE}"
echo "ca_dir=${CA_DIR}"
echo "total_in_bundle=$(grep -c 'BEGIN CERTIFICATE' "$CA_BUNDLE" 2>/dev/null || echo 0)"
echo "total_hash_links=$(find "$CA_DIR" -maxdepth 1 -type l -name '[0-9a-f]*.[0-9]' 2>/dev/null | wc -l)"
echo ""
echo "custom_certs="
for dir in /usr/local/share/ca-certificates/custom /usr/local/share/ca-certificates/llm; do
[ -d "$dir" ] || continue
for f in "$dir"/*.pem "$dir"/*.crt; do
[ -f "$f" ] || continue
subj="$(openssl x509 -in "$f" -noout -subject 2>/dev/null | head -1 || echo '?')"
issuer="$(openssl x509 -in "$f" -noout -issuer 2>/dev/null | head -1 || echo '?')"
fp="$(openssl x509 -in "$f" -noout -fingerprint -sha256 2>/dev/null | sed 's/.*=//' || echo '?')"
in_bundle="no"
grep -qF "$fp" "$CA_BUNDLE" 2>/dev/null && in_bundle="yes"
echo " $(basename $f) | subject=${subj} | issuer=${issuer} | in_bundle=${in_bundle}"
done
done
# ──────────────────────────────────────────────
# 2. OPENSSL s_client - 3 варианта
# ──────────────────────────────────────────────
echo ""
echo -e "${CYAN}── 2. OpenSSL s_client ──${NC}"
for variant in "CAfile=${CA_BUNDLE}" "CApath=${CA_DIR}" "default"; do
echo "variant=${variant}"
if [ "$variant" = "default" ]; then
out=$(openssl s_client -connect "${HOST}:443" -servername "$HOST" < /dev/null 2>&1)
else
key=$(echo "$variant" | cut -d= -f1)
val=$(echo "$variant" | cut -d= -f2-)
out=$(openssl s_client -connect "${HOST}:443" -"$key" "$val" -servername "$HOST" < /dev/null 2>&1)
fi
code=$(echo "$out" | grep "Verify return code" | head -1)
echo " result=${code}"
done
# ──────────────────────────────────────────────
# 3. Python - httpx (LLMClient style)
# ──────────────────────────────────────────────
echo ""
echo -e "${CYAN}── 3. Python httpx (как LLMClient) ──${NC}"
python3 -u -c '
import os, sys, ssl, traceback
target = os.environ.get("TARGET_URL", "https://lite.ai.rusal.com")
ca_bundle = "/etc/ssl/certs/ca-certificates.crt"
ca_dir = "/etc/ssl/certs"
results = {}
# A) SSLContext s cafile
try:
ctx = ssl.create_default_context(cafile=ca_bundle)
import httpx
r = httpx.get(target, verify=ctx, timeout=10)
results["httpx+cafile"] = f"OK status={r.status_code}"
except Exception as e:
results["httpx+cafile"] = f"FAIL {type(e).__name__}: {e}"
# B) SSLContext s cafile + capath
try:
ctx2 = ssl.create_default_context()
ctx2.load_verify_locations(cafile=ca_bundle)
if os.path.isdir(ca_dir):
ctx2.load_verify_locations(capath=ca_dir)
import httpx
r = httpx.get(target, verify=ctx2, timeout=10)
results["httpx+cafile+capath"] = f"OK status={r.status_code}"
except Exception as e:
results["httpx+cafile+capath"] = f"FAIL {type(e).__name__}: {e}"
# C) requests s verify=cafile
try:
import requests
r = requests.get(target, verify=ca_bundle, timeout=10)
results["requests+cafile"] = f"OK status={r.status_code}"
except Exception as e:
results["requests+cafile"] = f"FAIL {type(e).__name__}: {e}"
# D) requests s verify=capath
try:
import requests
r = requests.get(target, verify=ca_dir, timeout=10)
results["requests+capath"] = f"OK status={r.status_code}"
except Exception as e:
results["requests+capath"] = f"FAIL {type(e).__name__}: {e}"
for k, v in results.items():
print(f" {k}={v}")
' 2>&1
# ──────────────────────────────────────────────
# 4. NSS / Chromium
# ──────────────────────────────────────────────
echo ""
echo -e "${CYAN}── 4. NSS Chromium ──${NC}"
if command -v certutil &>/dev/null && certutil -L -d "$NSS_DB" >/dev/null 2>&1; then
echo "nss_db=${NSS_DB}"
echo "nss_certs_count=$(certutil -L -d "$NSS_DB" 2>/dev/null | wc -l)"
echo "nss_custom_certs="
certutil -L -d "$NSS_DB" 2>/dev/null | grep -iE "rusal|llm-|custom-" | while read -r line; do
echo " $line"
done
else
echo "nss_db=unavailable"
fi
# ──────────────────────────────────────────────
# 5. LLM_SSL_VERIFY env
# ──────────────────────────────────────────────
echo ""
echo -e "${CYAN}── 5. LLM_SSL_VERIFY ──${NC}"
raw="${LLM_SSL_VERIFY:-not_set}"
echo "LLM_SSL_VERIFY=${raw}"
# doporuceni
echo ""
echo -e "${CYAN}── 6. AI Recommendation Input ──${NC}"
echo "To fix SSL issues, AI needs to know which methods work."
echo "Copy the FULL output above and paste to the AI assistant."