Как да управляваш DirectAdmin хостинг акаунт изцяло с AI агенти през SSH

V3 е най-силната версия досега и вече личи, че е минала през реални тестове, а не само през теоретичен review. Live-verified секцията е особено ценна: вече са документирани конкретни особености на CoolIceHost при subdomains, PHP selector, DNS/MX, force_ssl, WordPress quick installer, MariaDB dump и Softaculous.

Но открих два важни логически конфликта и няколко по-малки проблема.

1. Delete policy вече противоречи на самия runbook — това е най-важният проблем​

Глобалното правило е абсолютно:

NEVER delete anything without explicit confirmation in the current conversation.


Но runbook-ът сам извършва множество автоматични изтривания без такава confirmation:

rm -rf "$DA_SESSION"
rm -f "$tmp"
rm -f "$CNF"
rm -f "$PROBE"
и казва да се изтрие EICAR test файлът след тест. Session cleanup конкретно е автоматичен trap с rm -rf.

Това поставя AI агента в невъзможна ситуация: най-високоприоритетното правило му забранява да изпълни собствената bootstrap логика.

Трябва изрично изключение, примерно:

Ephemeral files/directories created by the agent during the current session solely for temporary operation (DA_SESSION, curl bodies, generated probes, temporary .cnf, explicitly created test files) may be removed automatically. This exception never applies to pre-existing user data, application files, uploads, backups, domains, databases or mail.
Това според мен е P0 policy fix.


2. Hard rule за main password противоречи на Softaculous секцията​

В началото:

Never use the main account password if a Login Key exists.


Но вече е live-verified, че Softaculous изисква:

DirectAdmin account password once — SOFT_PASS
и Login Key не е достатъчен.

Това също е пряк policy конфликт.

Трябва hard rule да стане нещо от рода на:

Never use the main account password when a Login Key can perform the requested operation. Exception: a verified subsystem that does not accept Login Keys (currently CoolIceHost Softaculous panel session); explain why and request/use the password only for that operation.
Иначе правилният агент трябва да откаже Softaculous workflow-а, въпреки че самият runbook го предписва.


3. Quick Reference за Softaculous вече е грешен​

В Quick Reference още пише приблизително:

Softaculous | cli.php probe | --list / --install | --remove ...


А §29 категорично и live-verified казва:

SSH cli.php ... does not authenticate
--list/--remove are cPanel/Webuzo-only.
Working path: panel session cookie + plugin JSON API.


Това е реално опасно за AI, защото Quick Reference обикновено ще се използва като най-краткия authoritative lookup.

Трябва да стане например:

Softaculous | plugin JSON API | cookie session + index.raw?api=json | remove via act=remove

4. Quick Reference за Vacation също е остарял​

Таблицата още сочи CMD_API_EMAIL_VACATION.

Но основната секция вече правилно казва:

Prefer the modern API — legacy CMD_API_EMAIL_VACATION create wants every start/end time field and is easy to get wrong.
и използва /api/emailvacation/....

Таблицата трябва да отразява modern API.


5. Quick Reference за Catch-all е подвеждащ за CoolIceHost​

Там още изглежда като поддържана операция:

Catch-all | CMD_API_EMAIL_CATCH_ALL | same | prefer :fail:
Но основният текст казва:

CoolIceHost: catch-all is disabled on most servers. Do not try to enable it. Do not recommend it.


За CoolIceHost-specific runbook quick reference трябва да казва:

Catch-all | probe only | normally disabled on CoolIceHost | do not enable

6. Softaculous login JSON има реален quoting bug​

Това:

--data "{\"username\":\"$DA_USER\",\"password\":\"$SOFT_PASS\"}"


ще се счупи, ако password съдържа например " или \.

При password не бива да се конструира JSON чрез shell interpolation.

По-безопасно:

python3 -c 'import json,os; print(json.dumps({
"username": os.environ["DA_USER"],
"password": os.environ["SOFT_PASS"]
}))'
и output-ът да отиде към curl --data-binary @-.

Допълнителен плюс: така password не стои като част от curl command argument.

Това е реален code fix, не само hardening.


7. DirectAdmin credentials също остават в process argv​

Навсякъде има:

curl --user "$DA_USER:$DA_PASS"
Например wrapper-ът го използва централизирано.

Това означава Login Key да се появи временно в process arguments. За shared CageFS рискът е ограничен, но документът е доста строг по отношение на secrets.

Има два варианта:

  • да използвате curl --config/temporary 600 config;
  • или да го документирате като accepted residual risk, както вече е направено с WP-CLI credentials.
Не е blocker, но в момента security policy е малко непоследователен.


8.​

Тук корекцията е добра. Вече не приема произволно foo=bar; има known-key validation:

known = {"error", "text", "details", "success", ...}
и неизвестните responses fail-ват.

Това вече бих го считал за решено.


9. Session race condition също е решен добре​

Преминаването към:

DA_SESSION=$(mktemp -d ...)
DA_HTTP_FILE="$DA_SESSION/http"
е правилното решение и премахва проблема с два едновременни SSH/agent sessions.

Освен гореспоменатия конфликт с delete policy, реализацията ми харесва.


10. MariaDB корекцията е важна и вече изглежда реално grounded​

Тук V3 е значително по-силен:

DUMPBIN="$(command -v mariadb-dump || command -v mysqldump)"
"$DUMPBIN" --defaults-file="$CNF"
и изрично е документирано, че на конкретната CoolIceHost MariaDB 11.8 конфигурация --defaults-extra-fileне работи както се очаква.

Точно такъв тип live verification прави документа полезен.


11. ZIP workflow вече е на добро ниво​

Има:

  • path traversal validation;
  • symlink rejection;
  • collision listing;
  • confirmation;
  • SHA-256 check между list и extract.


Това вече е много добра реализация за agent runbook. Тук нямам съществена забележка.


12. Composer секцията вече е практически завършена​

Поправени са:

  • timestamped backups;
  • conditional composer.lock;
  • --update-no-dev за Composer 2.10;
  • разграничението между dependency rollback и Composer-script side effects.


Това адресира предишните ми основни забележки.


13. Структурата вече е подобрена логически​

Промяната:

Keep §1–§3 for every session. For a narrow job you may skip later sections...
е много по-добра от старото безусловно „paste all 1700 lines“.

Така compiled документът може да остане един, без непременно всяка задача да носи целия context.

Бих оставил това така.


14. Live-verified секцията е една от най-добрите части на V3​

Тя отделя „как принципно работи DirectAdmin“ от „какво реално установихме на CoolIceHost на 21.08.2026“.

Това решава голям проблем от ранните версии: примерите вече не се представят безкритично като универсални.

Единствено бих добавил към заглавието/началото:

When §30 conflicts with a generic example, §30 wins for the verified CoolIceHost stack unless a new probe disproves it.
Това формализира приоритета.

Финална оценка​

V3 вече бих оценил така:

Policy/safety: 9/10, но става 9.7 след изчистването на двата големи противоречиви правила — delete на ephemeral файлове и main password/Softaculous.

Executable examples: 9.3/10. Основният конкретен бъг, който виждам сега, е ръчно конструираният Softaculous login JSON.

CoolIceHost-specific reliability: 9.5/10. Live testing е вдигнал документа много.

Структура: 9/10.

Общо: около 9.2/10 в сегашния вид.

Преди да го приема за финален, бих оправил точно пет неща: exception за agent-created temporary deletes; exception за panel password при verified unsupported-by-Login-Key subsystem; Softaculous login JSON; Quick Reference редовете за Softaculous/Vacation/Catch-all; и explicit правило, че live-verified §30 има предимство пред generic пример при конфликт.

След това вече не виждам причина да се правят още големи архитектурни промени — следващият етап е regression/integration testing, не ново пренаписване.
 
Вкарах петте му пункта плюс JSON quoting и curl --config. v3.1, без нова архитектура.


#Какво казаКакво направихме
1Delete vs rm -rf "$DA_SESSION"§2: изключение само за ефимерни файлове от тази сесия
2Login Key vs SoftaculousHard rule: парола само за verified subsystem, само за тази операция
3–5Quick Reference лъжеSoftaculous → index.raw; Vacation → /api/emailvacation; Catch-all → disabled
6"$SOFT_PASS" в JSONjson.dumps + --data-binary @-
7--user в argvWrapper: -K "$DA_CURL_CFG" mode 600. TLS probe остава one-shot residual
14§30 vs genericИзрично: §30 печели, освен ако нов probe не го опровергае


Не пипахме в 3.1 — Codex ги отбеляза като решени още в 3.0:


#ТемаЗащо
8json_or_qs known keysfail-closed вече
9Session raceDA_SESSION=$(mktemp -d)
10mariadb-dump --defaults-filelive-verified
11ZIP path/symlink/collision/SHAбез забележка
12Composer --update-no-dev, backupзавършено
13„дръж §1–§3, останалото по задача“остави го така


вкарано в change log на първа страница

v3.1 — policy consistency след бележките на Sky: ефимерните session файлове може да се чистят без YES; паролата на панела е изключение само за Softaculous; Quick Reference вече съвпада с live-verified секцията; Softaculous login JSON вече не се лепи през shell.

Версията е live надявам се всичко вече е 9.5+ / 10 :)
 
Да. Този път бих го третирал като финален review, а не като търсене на още неща на всяка цена.

V3.1 е значително изчистен. Всичките пет важни забележки от предния анализ са нанесени: ephemeral delete exception, изключението за main password при Softaculous, безопасното JSON подаване при login, поправеният Quick Reference и формалният приоритет на §30.

Какво вече считам за решено​

Delete policy вече е логически последователен. Временните файлове, които самият агент създава в текущата сесия, са ясно изключени, без това да отваря врата за изтриване на потребителски данни. Формулировката е добра.

Credential handling също е на добро ниво. DirectAdmin credentials вече се записват в session-specific curl.cfg с mode 600 и curl използва -K, вместо Login Key да стои в argv. Session directory решава и concurrency проблема.

json_or_qs вече е fail-closed достатъчно добре: HTML, malformed JSON, неизвестен plain response и непознат query-string се отхвърлят.

Softaculous login JSON вече не се строи чрез unsafe shell interpolation, а през json.dumps(). Това оправя реалния quoting bug от V3.

Quick Reference вече съвпада с реално установеното за Vacation, Catch-all и Softaculous.

Остават няколко дребни неща​

1. mysql_cnf() все още подава DB password като argv към Python.

python3 -c '...' "$1" "$2"
Тоест за краткия живот на процеса DB password е command-line argument на python3.

А непосредствено след това runbook-ът казва:

Do not pass DB/FTP passwords on ps-visible argv


Това е малко вътрешно противоречие.

Може да се оправи чрез environment:

MYSQL_CNF_USER="$1" MYSQL_CNF_PASS="$2" python3 -c '... os.environ[...] ...'
Това е единственото останало нещо, което бих определил като действителен code/policy inconsistency.


2. Softaculous install пак подава admin_pass като curl argv.

--data-urlencode admin_pass="$P"


Тук също credential може временно да се вижда в process list.

Не е голям проблем в CageFS и вече имате подобен accepted residual risk за WP-CLI. Просто бих добавил същото уточнение за Softaculous или бих подавал POST body през stdin/config.


3. WordPress uninstall е описан опасно близо до executable инструкция без непосредствен confirmation warning.

Има:

DELETE /api/wordpress/locations/{id} → 204, drops the WP DB.


Глобалният §2 безспорно го забранява без confirmation. Но точно защото тази операция изтрива и DB, бих написал на същото място:

Uninstall is destructive — §2 confirmation required; it drops the WP database.
Това е defense-in-depth срещу AI context dilution.


4. Subdomain Quick Reference казва contents=yes, докато основната политика казва default contents=no.

Quick Reference:

Subdomains ... delete select0= + contents=yes


Но §2:

Prefer contents=no unless they explicitly want files deleted.


И §9 също правилно използва contents=no.

Разбирам защо contents=yes е в таблицата — §30 казва, че това реално премахва vhost tree. Но Quick Reference може да подтикне агента към по-разрушителната операция.

Бих написал:

delete: contents=no default; contents=yes only if confirmed files must go
Това си струва да се оправи.


5. §30 също може да формулира subdomain delete по-безопасно.

В момента:

Delete select0= + contents=yes.


Технически това е live-verified факт, но понеже §30 има изричен приоритет над generic examples, агентът може да го интерпретира като препоръчителния начин.

По-добре:

contents=no removes the DA subdomain while preserving files; contents=yes also removes the vhost tree and requires explicit confirmation for file deletion.
Така запазваш live finding-а, без да променяш safety semantics.

Един текстов детайл​

В §5.1 имаш едновременно:

  • $HOME/.cl.selector or $HOME/.cagefs exists
  • ~/.cl.selector exists
Тоест .cl.selector е повторено два пъти.

Само редакционен шум.

Финална оценка​

Вече бих дал:

  • Safety/policy: 9.7/10
  • Executable examples: 9.5/10
  • Internal consistency: 9.5/10
  • CoolIceHost-specific usefulness: 10/10
  • Общо: ~9.6/10
И тук бих спрял с архитектурните ревюта.

Поправи mysql_cnf argv и subdomain contents=yes формулировката. Другите две са optional hardening.

След това по-голяма стойност ще има да поддържате §30 при реални промени в DirectAdmin/CloudLinux/CoolIceHost, отколкото да продължаваме да полираме документа. Вече не виждам фундаментален проблем, който да оправдава ново пренаписване.
 

Горе