410 lines
13 KiB
Bash
Executable File
410 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# End-to-end execution for P0/P1/P2 with reporting.
|
|
|
|
BASE_URL="${BASE_URL:-https://weval-consulting.com}"
|
|
SENTINEL_URL="${SENTINEL_URL:-http://89.167.40.150:5890/api/sentinel-brain.php}"
|
|
TRACKING_BASE_URL="${TRACKING_BASE_URL:-http://151.80.235.110}"
|
|
TRACKING_DOMAIN_URL="${TRACKING_DOMAIN_URL:-https://culturellemejean.charity}"
|
|
GPU_MODEL="${GPU_MODEL:-qwen2.5:3b}"
|
|
INPUT_API_KEY="${API_KEY:-}"
|
|
APPLY_SAFE_FIXES="${APPLY_SAFE_FIXES:-1}"
|
|
STRICT_CONFIDENTIALITY="${STRICT_CONFIDENTIALITY:-1}"
|
|
SERVERS_CSV="${SERVERS_CSV:-}"
|
|
HUAWEI_STANDBY="${HUAWEI_STANDBY:-0}"
|
|
|
|
REPORT_DIR="${REPORT_DIR:-./reports}"
|
|
RUN_ID="$(date +%Y%m%d_%H%M%S)"
|
|
REPORT_FILE="${REPORT_DIR}/p0_p1_p2_execution_${RUN_ID}.md"
|
|
RAW_DIR="${REPORT_DIR}/raw_${RUN_ID}"
|
|
mkdir -p "${REPORT_DIR}" "${RAW_DIR}"
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
WARN=0
|
|
declare -a FAILS
|
|
declare -a WARNS
|
|
|
|
pass() { PASS=$((PASS+1)); echo "PASS | $*"; }
|
|
fail() { FAIL=$((FAIL+1)); FAILS+=("$*"); echo "FAIL | $*"; }
|
|
warn() { WARN=$((WARN+1)); WARNS+=("$*"); echo "WARN | $*"; }
|
|
|
|
sentinel_exec() {
|
|
local cmd="$1"
|
|
python3 - "$SENTINEL_URL" "$cmd" <<'PY'
|
|
import json,sys,requests
|
|
url=sys.argv[1]
|
|
cmd=sys.argv[2]
|
|
r=requests.post(url,data={'action':'exec','cmd':cmd},timeout=120)
|
|
print(r.text)
|
|
PY
|
|
}
|
|
|
|
extract_json_field() {
|
|
local key="$1" file="$2"
|
|
python3 - "$key" "$file" <<'PY'
|
|
import json,sys
|
|
k=sys.argv[1]; f=sys.argv[2]
|
|
obj=json.load(open(f))
|
|
print(obj.get(k,""))
|
|
PY
|
|
}
|
|
|
|
echo "=== P0/P1/P2 EXECUTION START ${RUN_ID} ==="
|
|
|
|
# ------------------------------------------------------------
|
|
# P0.1 - Acquire API key for strict testing
|
|
# ------------------------------------------------------------
|
|
echo "== P0.1 Acquire API key =="
|
|
if [[ -n "${INPUT_API_KEY}" ]]; then
|
|
API_KEY="${INPUT_API_KEY}"
|
|
pass "Using provided API_KEY from environment"
|
|
else
|
|
python3 - "${BASE_URL}" "${RAW_DIR}/auth.json" <<'PY'
|
|
import requests,sys,time,json,uuid
|
|
base=sys.argv[1]
|
|
out=sys.argv[2]
|
|
email=f"codex.auto.{int(time.time())}.{uuid.uuid4().hex[:6]}@weval.test"
|
|
payload={
|
|
"name":"Codex Auto",
|
|
"email":email,
|
|
"company":"WEVAL QA",
|
|
"phone":"+33123456789",
|
|
"product":"gpu-inference"
|
|
}
|
|
r=requests.post(f"{base}/api/products/auth.php",json=payload,timeout=30)
|
|
data={"http":r.status_code,"body":r.text,"email":email}
|
|
try:
|
|
j=r.json()
|
|
data["api_key"]=j.get("api_key","")
|
|
except Exception:
|
|
data["api_key"]=""
|
|
json.dump(data,open(out,"w"),indent=2)
|
|
print(data["api_key"])
|
|
PY
|
|
API_KEY="$(extract_json_field api_key "${RAW_DIR}/auth.json")"
|
|
if [[ -z "${API_KEY}" ]]; then
|
|
# Fallback: reuse latest known api_key from previous runs
|
|
API_KEY="$(python3 - <<'PY'
|
|
import glob,json,os
|
|
keys=[]
|
|
for p in sorted(glob.glob('reports/raw_*/auth.json'), reverse=True):
|
|
try:
|
|
j=json.load(open(p))
|
|
except Exception:
|
|
continue
|
|
k=j.get('api_key','')
|
|
if k:
|
|
print(k)
|
|
break
|
|
PY
|
|
)"
|
|
fi
|
|
if [[ -n "${API_KEY}" ]]; then
|
|
pass "API key available for strict tests"
|
|
else
|
|
fail "Unable to obtain or reuse API key"
|
|
fi
|
|
fi
|
|
|
|
# ------------------------------------------------------------
|
|
# P0.2 - Strict anti-regression gate
|
|
# ------------------------------------------------------------
|
|
echo "== P0.2 Strict anti-regression gate =="
|
|
if API_KEY="${API_KEY}" STRICT_CONFIDENTIALITY="${STRICT_CONFIDENTIALITY}" \
|
|
TRACKING_BASE_URL="${TRACKING_BASE_URL}" TRACKING_DOMAIN_URL="${TRACKING_DOMAIN_URL}" \
|
|
GPU_MODEL="${GPU_MODEL}" /workspace/nonreg-framework.sh > "${RAW_DIR}/nonreg.out" 2>&1; then
|
|
pass "Strict anti-regression completed without hard failure"
|
|
else
|
|
fail "Strict anti-regression returned failures (see raw logs)"
|
|
fi
|
|
|
|
# ------------------------------------------------------------
|
|
# P0.3 - Multi-install preflight
|
|
# ------------------------------------------------------------
|
|
echo "== P0.3 Multi-install preflight =="
|
|
if [[ "${HUAWEI_STANDBY}" == "1" ]]; then
|
|
warn "Huawei standby mode active: multi-install preflight skipped by policy"
|
|
elif [[ -n "${SERVERS_CSV}" && -f "${SERVERS_CSV}" ]]; then
|
|
if /workspace/multiinstall-safe-preflight.sh "${SERVERS_CSV}" > "${RAW_DIR}/preflight.out" 2>&1; then
|
|
# Evaluate readiness quality
|
|
PREF_FILE="$(python3 - <<'PY'
|
|
import glob
|
|
files=sorted(glob.glob('reports/multiinstall_preflight_*.csv'))
|
|
print(files[-1] if files else '')
|
|
PY
|
|
)"
|
|
if [[ -n "${PREF_FILE}" ]]; then
|
|
READY_COUNT="$(python3 - "${PREF_FILE}" <<'PY'
|
|
import csv,sys
|
|
f=sys.argv[1]
|
|
ready=0
|
|
for row in csv.DictReader(open(f)):
|
|
if row.get('ready')=='YES':
|
|
ready+=1
|
|
print(ready)
|
|
PY
|
|
)"
|
|
if [[ "${READY_COUNT}" -gt 0 ]]; then
|
|
pass "Multi-install preflight executed (${READY_COUNT} ready servers)"
|
|
else
|
|
fail "Multi-install preflight executed but 0 ready servers"
|
|
fi
|
|
else
|
|
warn "Multi-install preflight executed but no CSV artifact detected"
|
|
fi
|
|
else
|
|
fail "Multi-install preflight execution failed"
|
|
fi
|
|
else
|
|
warn "SERVERS_CSV not provided; multi-install preflight skipped"
|
|
fi
|
|
|
|
# ------------------------------------------------------------
|
|
# P1 - Ethica + Tracking reliability checks and safe fixes
|
|
# ------------------------------------------------------------
|
|
echo "== P1 Ethica/Tracking reliability =="
|
|
|
|
S_IDENTITY="${RAW_DIR}/sentinel_identity.json"
|
|
sentinel_exec "whoami && hostname" > "${S_IDENTITY}" || true
|
|
if rg -n "\"ok\":true" "${S_IDENTITY}" >/dev/null; then
|
|
pass "Sentinel command channel reachable"
|
|
else
|
|
fail "Sentinel command channel unreachable"
|
|
fi
|
|
|
|
S_COUNT="${RAW_DIR}/ethica_count.json"
|
|
sentinel_exec "PGPASSWORD=admin123 psql -h 127.0.0.1 -U admin -d adx_system -Atc \"SELECT count(*) FROM ethica.medecins_real;\"" > "${S_COUNT}" || true
|
|
if rg -n "\"ok\":true" "${S_COUNT}" >/dev/null; then
|
|
pass "Ethica DB count query executed"
|
|
else
|
|
fail "Ethica DB count query failed"
|
|
fi
|
|
|
|
S_TABIBI="${RAW_DIR}/tabibi_check.json"
|
|
sentinel_exec "[ -f /opt/wevads/scripts/ethica/scraper-tabibi.php ] && sed -n '1,40p' /opt/wevads/scripts/ethica/scraper-tabibi.php || echo MISSING" > "${S_TABIBI}" || true
|
|
if rg -n -i "listing-based" "${S_TABIBI}" >/dev/null; then
|
|
pass "Tabibi scraper is listing-based"
|
|
else
|
|
warn "Tabibi scraper listing mode not confirmed"
|
|
fi
|
|
|
|
S_1SANTE="${RAW_DIR}/onesante_check.json"
|
|
sentinel_exec "[ -f /opt/wevads/scripts/ethica/scraper-1sante.php ] && echo FOUND || echo MISSING" > "${S_1SANTE}" || true
|
|
if rg -n "FOUND" "${S_1SANTE}" >/dev/null; then
|
|
pass "1sante scraper script present"
|
|
else
|
|
warn "1sante scraper script missing at expected path"
|
|
fi
|
|
|
|
S_LOGROTATE="${RAW_DIR}/logrotate_check_before.json"
|
|
sentinel_exec "[ -f /etc/logrotate.d/ethica ] && echo EXISTS || echo MISSING" > "${S_LOGROTATE}" || true
|
|
if rg -n "EXISTS" "${S_LOGROTATE}" >/dev/null; then
|
|
pass "Ethica logrotate config already present"
|
|
elif [[ "${APPLY_SAFE_FIXES}" == "1" ]]; then
|
|
S_FIX_LOGROTATE="${RAW_DIR}/fix_logrotate.json"
|
|
sentinel_exec "cat > /etc/logrotate.d/ethica <<'EOF'
|
|
/opt/wevads/logs/ethica*.log {
|
|
daily
|
|
rotate 14
|
|
missingok
|
|
notifempty
|
|
compress
|
|
delaycompress
|
|
copytruncate
|
|
create 0640 www-data www-data
|
|
}
|
|
EOF
|
|
echo CREATED" > "${S_FIX_LOGROTATE}" || true
|
|
if rg -n "CREATED" "${S_FIX_LOGROTATE}" >/dev/null; then
|
|
pass "Applied Ethica logrotate safe fix"
|
|
else
|
|
fail "Failed to apply Ethica logrotate safe fix"
|
|
fi
|
|
else
|
|
warn "Ethica logrotate missing (safe fixes disabled)"
|
|
fi
|
|
|
|
S_TRACKING_URL="${RAW_DIR}/tracking_url_before.json"
|
|
sentinel_exec "python3 - <<'PYN'
|
|
import json
|
|
p='/opt/fmgapp/config/application.json'
|
|
obj=json.load(open(p))
|
|
print(obj.get('application',{}).get('tracking_url','MISSING'))
|
|
PYN" > "${S_TRACKING_URL}" || true
|
|
|
|
if rg -n "culturellemejean\\.charity" "${S_TRACKING_URL}" >/dev/null; then
|
|
pass "FMG tracking_url already set"
|
|
elif [[ "${APPLY_SAFE_FIXES}" == "1" ]]; then
|
|
S_FIX_TRACKING="${RAW_DIR}/fix_tracking_url.json"
|
|
sentinel_exec "python3 - <<'PYN'
|
|
import json, shutil, time
|
|
p='/opt/fmgapp/config/application.json'
|
|
bak=f\"{p}.bak_{int(time.time())}\"
|
|
obj=json.load(open(p))
|
|
app=obj.setdefault('application',{})
|
|
if app.get('tracking_url')!='https://culturellemejean.charity':
|
|
shutil.copy2(p,bak)
|
|
app['tracking_url']='https://culturellemejean.charity'
|
|
json.dump(obj,open(p,'w'),ensure_ascii=False,indent=4)
|
|
print('tracking_url=',app.get('tracking_url'))
|
|
PYN" > "${S_FIX_TRACKING}" || true
|
|
if rg -n "culturellemejean\\.charity" "${S_FIX_TRACKING}" >/dev/null; then
|
|
pass "Applied FMG tracking_url safe fix"
|
|
else
|
|
fail "Failed to apply FMG tracking_url safe fix"
|
|
fi
|
|
else
|
|
warn "FMG tracking_url missing (safe fixes disabled)"
|
|
fi
|
|
|
|
S_TRACKING_URL_WEVADS="${RAW_DIR}/tracking_url_wevads_before.json"
|
|
sentinel_exec "python3 - <<'PYN'
|
|
import json
|
|
p='/opt/wevads/config/application.json'
|
|
try:
|
|
obj=json.load(open(p))
|
|
print(obj.get('application',{}).get('tracking_url','MISSING'))
|
|
except Exception as e:
|
|
print('ERROR', e)
|
|
PYN" > "${S_TRACKING_URL_WEVADS}" || true
|
|
|
|
if rg -n "culturellemejean\\.charity" "${S_TRACKING_URL_WEVADS}" >/dev/null; then
|
|
pass "WEVADS tracking_url already set"
|
|
elif [[ "${APPLY_SAFE_FIXES}" == "1" ]]; then
|
|
S_FIX_TRACKING_WEVADS="${RAW_DIR}/fix_tracking_url_wevads.json"
|
|
sentinel_exec "python3 - <<'PYN'
|
|
import json, shutil, time
|
|
p='/opt/wevads/config/application.json'
|
|
bak=f\"{p}.bak_{int(time.time())}\"
|
|
obj=json.load(open(p))
|
|
app=obj.setdefault('application',{})
|
|
if app.get('tracking_url')!='https://culturellemejean.charity':
|
|
shutil.copy2(p,bak)
|
|
app['tracking_url']='https://culturellemejean.charity'
|
|
json.dump(obj,open(p,'w'),ensure_ascii=False,indent=4)
|
|
print('tracking_url=',app.get('tracking_url'))
|
|
PYN" > "${S_FIX_TRACKING_WEVADS}" || true
|
|
if rg -n "culturellemejean\\.charity" "${S_FIX_TRACKING_WEVADS}" >/dev/null; then
|
|
pass "Applied WEVADS tracking_url safe fix"
|
|
else
|
|
fail "Failed to apply WEVADS tracking_url safe fix"
|
|
fi
|
|
else
|
|
warn "WEVADS tracking_url missing (safe fixes disabled)"
|
|
fi
|
|
|
|
# ------------------------------------------------------------
|
|
# P2 - Factory SaaS smoke/load checks
|
|
# ------------------------------------------------------------
|
|
echo "== P2 Factory SaaS smoke/load =="
|
|
|
|
python3 - "${BASE_URL}" "${API_KEY}" "${GPU_MODEL}" "${RAW_DIR}/p2_api_results.json" <<'PY'
|
|
import requests,sys,time,json,concurrent.futures
|
|
base,key,model,out=sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4]
|
|
|
|
def hit(url,method='GET',headers=None,json_body=None):
|
|
t0=time.time()
|
|
try:
|
|
if method=='GET':
|
|
r=requests.get(url,timeout=120,headers=headers)
|
|
else:
|
|
r=requests.post(url,timeout=120,headers=headers,json=json_body)
|
|
return {"code":r.status_code,"time":round(time.time()-t0,3),"body":r.text[:300]}
|
|
except Exception as e:
|
|
return {"code":0,"time":round(time.time()-t0,3),"error":str(e)}
|
|
|
|
tests=[
|
|
("deliver", lambda: hit(f"{base}/api/deliverscore/scan.php?domain=gmail.com&api_key={key}")),
|
|
("medreach", lambda: hit(f"{base}/api/medreach/search.php?specialty=cardiologue&country=FR&limit=10&api_key={key}")),
|
|
("content", lambda: hit(f"{base}/api/content/generate.php",method='POST',headers={"X-API-Key":key,"Content-Type":"application/json"},json_body={"template":"linkedin_post","topic":"test","language":"fr"})),
|
|
("gpu", lambda: hit(f"{base}/api/gpu/chat.php",method='POST',headers={"X-API-Key":key,"Content-Type":"application/json"},json_body={"model":model,"messages":[{"role":"user","content":"Donne 3 points deliverabilite"}]})),
|
|
]
|
|
|
|
results={}
|
|
for name,fn in tests:
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
|
|
arr=list(ex.map(lambda _: fn(), range(3)))
|
|
results[name]=arr
|
|
|
|
json.dump(results,open(out,'w'),indent=2)
|
|
print("done")
|
|
PY
|
|
|
|
for test in deliver medreach content gpu; do
|
|
if python3 - "${RAW_DIR}/p2_api_results.json" "${test}" <<'PY'
|
|
import json,sys
|
|
f,t=sys.argv[1],sys.argv[2]
|
|
arr=json.load(open(f))[t]
|
|
ok=sum(1 for x in arr if x.get("code")==200 and "Model not available" not in (x.get("body") or ""))
|
|
print(ok)
|
|
PY
|
|
then
|
|
OK_COUNT="$(python3 - "${RAW_DIR}/p2_api_results.json" "${test}" <<'PY'
|
|
import json,sys
|
|
f,t=sys.argv[1],sys.argv[2]
|
|
arr=json.load(open(f))[t]
|
|
ok=sum(1 for x in arr if x.get("code")==200 and "Model not available" not in (x.get("body") or ""))
|
|
print(ok)
|
|
PY
|
|
)"
|
|
if [[ "${OK_COUNT}" -ge 2 ]]; then
|
|
pass "P2 ${test}: ${OK_COUNT}/3 successful"
|
|
else
|
|
fail "P2 ${test}: only ${OK_COUNT}/3 successful"
|
|
fi
|
|
else
|
|
fail "P2 ${test}: result parsing failed"
|
|
fi
|
|
done
|
|
|
|
# ------------------------------------------------------------
|
|
# Final report
|
|
# ------------------------------------------------------------
|
|
{
|
|
echo "# Rapport execution P0/P1/P2 ${RUN_ID}"
|
|
echo
|
|
echo "- Base URL: ${BASE_URL}"
|
|
echo "- Sentinel URL: ${SENTINEL_URL}"
|
|
echo "- Safe fixes applied: ${APPLY_SAFE_FIXES}"
|
|
echo "- Strict confidentiality: ${STRICT_CONFIDENTIALITY}"
|
|
echo "- Huawei standby mode: ${HUAWEI_STANDBY}"
|
|
echo
|
|
echo "## Resume"
|
|
echo "- PASS: ${PASS}"
|
|
echo "- WARN: ${WARN}"
|
|
echo "- FAIL: ${FAIL}"
|
|
echo
|
|
if (( WARN > 0 )); then
|
|
echo "## Warnings"
|
|
printf -- "- %s\n" "${WARNS[@]}"
|
|
echo
|
|
fi
|
|
if (( FAIL > 0 )); then
|
|
echo "## Failures"
|
|
printf -- "- %s\n" "${FAILS[@]}"
|
|
echo
|
|
fi
|
|
echo "## Artefacts"
|
|
echo "- Raw outputs: ${RAW_DIR}/"
|
|
echo "- Nonreg report(s): reports/nonreg_*.md"
|
|
echo "- Preflight report(s): reports/multiinstall_preflight_*.csv"
|
|
echo "- P2 API result: ${RAW_DIR}/p2_api_results.json"
|
|
echo
|
|
echo "## Verdict"
|
|
if (( FAIL == 0 )); then
|
|
echo "GO (P0/P1/P2 executed without hard failure)."
|
|
else
|
|
echo "CONDITIONNEL (${FAIL} hard failures require action)."
|
|
fi
|
|
} > "${REPORT_FILE}"
|
|
|
|
echo "Report written: ${REPORT_FILE}"
|
|
echo "=== P0/P1/P2 EXECUTION END ${RUN_ID} ==="
|
|
|
|
if (( FAIL > 0 )); then
|
|
exit 1
|
|
fi
|
|
|