diff --git a/DOCS/sonnet-response-final.md b/DOCS/sonnet-response-final.md new file mode 100644 index 0000000..027ab4a --- /dev/null +++ b/DOCS/sonnet-response-final.md @@ -0,0 +1,19 @@ +# Sonnet 4.6 — Финальный аудит + +Дата: 2026-07-30 + +## 5 багов в app.js + +| # | Баг | Строка | +|---|-----|--------| +| 🔴1 | `d.operations.filter` без null-guard | toggleInstance | +| 🔴2 | toggleInstance без try/catch | toggleInstance | +| 🔴3 | selectService без try/catch | selectService | +| 🔴4 | refreshInstances без try/catch | refreshInstances | +| 🟡5 | CMDB OK + refreshInstances → ошибка перезаписывает успех | executeOp | + +## redeploy без _send_params_terraform +Намеренно — redeploy переиспользует текущие params из state. + +## Бэкенд чист +api_test.py, main.py, get_params.py, http_client.py — багов нет. diff --git a/site/app.py b/site/app.py index 25707c5..da368da 100644 --- a/site/app.py +++ b/site/app.py @@ -18,7 +18,7 @@ from routes.api import bp as api_bp from routes.api_test import bp as api_test_bp # Версия — меняется при КАЖДОМ изменении кода. Показывается в топбаре UI. -VERSION = "1.1.43" +VERSION = "1.1.44" app = Flask(__name__, template_folder="templates", static_folder="static") app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc") diff --git a/site/static/app.js b/site/static/app.js index c58bb0e..d8ee292 100644 --- a/site/static/app.js +++ b/site/static/app.js @@ -46,6 +46,7 @@ async function selectService(svcId){ const svcEl=document.querySelector(`.svc-item[onclick*="${svcId}"]`); if(svcEl) svcEl.classList.add('active'); + try{ const r=await fetch('/api/operations/'+svcId); const d=await r.json(); svcInstances=d.instances||[]; @@ -67,6 +68,7 @@ async function selectService(svcId){ html+=`
`; }); document.getElementById('inst-list').innerHTML=html; + }catch(e){document.getElementById('inst-list').innerHTML='Ошибка загрузки';} } async function toggleInstance(iuid){ @@ -81,9 +83,10 @@ async function toggleInstance(iuid){ // Операции для ИНСТАНСА, не для выбранного сервиса const inst=svcInstances.find(x=>x.instanceUid===iuid); const svcId=inst?inst.serviceId:currentSvcId; + try{ const r=await fetch('/api/operations/'+svcId); const d=await r.json(); - let ops=d.operations.filter(o=>o.operation!=='reconcile'&&o.operation!=='create'); + let ops=(d.operations||[]).filter(o=>o.operation!=='reconcile'&&o.operation!=='create'); if(inst&&(inst.status||inst.explainedStatus)==='not created'){ ops=ops.filter(o=>o.operation==='delete'); } @@ -91,6 +94,7 @@ async function toggleInstance(iuid){ `` ).join(''); opsEl.classList.add('open'); + }catch(e){opsEl.innerHTML='Ошибка загрузки';opsEl.classList.add('open');} } function opClass(opName){ @@ -338,8 +342,8 @@ async function executeOp(params){ if(d.status==='OK'&&(d.opUid||'').startsWith('cmdb-')){ busy=false; setFinishedState('OK','badge-success','',0,d.displayName); - await refreshInstances(); - if(historyOpen) await loadHistory(); + try{await refreshInstances();}catch(e){} + if(historyOpen) try{await loadHistory();}catch(e){} return; } // start polling @@ -390,6 +394,7 @@ function stopPoll(){ } async function refreshInstances(){ + try{ const r=await fetch('/api/operations/'+currentSvcId); const d=await r.json(); const newInsts=d.instances||[]; @@ -406,6 +411,7 @@ async function refreshInstances(){ html+=``; }); document.getElementById('inst-list').innerHTML=html; + }catch(e){} } // === История тестов ===