# Madagascar Local Authority MVP

Madagascar Local Authority este o aplicație web locală, Perl-only, pentru registrul de hosturi Madagascar, manifestele DNS locale, Work Orders și autoritatea locală de certificate. Nu folosește npm, pip sau pachete CPAN instalate direct pe host.

Numele de produs este `Madagascar Local Authority`. Numele tehnic al serviciului, userului Unix, path-ului și fișierelor de environment rămâne `host-manager`.

Pentru deciziile de evoluție și schimbările de scope, vezi `.doc/development-log.md`.

## Politica de dependențe

Perl-ul livrat de distribuție este acceptat ca bază de runtime. Modulele Perl incluse în distribuție sau în core pot fi folosite direct.

Pachetele CPAN nu se instalează direct pe host cu `cpan`, `cpanm` sau mecanisme similare. Dacă aplicația are nevoie de un modul CPAN, modulul trebuie făcut disponibil prin repo-ul local după audit. Este acceptabilă o versiune mai veche/stabilă din repo-ul local; nu urmărim neapărat ultima versiune upstream.

MVP-ul curent nu are dependențe CPAN externe.

## Rol

`config/hosts.yaml` este registrul editabil și trebuie menținut în git. Aplicația este complet în spatele autentificării OTP pentru orice date de registru, exporturi sau modificări.

Git rămâne mecanismul de audit, istoric și rollback. Aplicația nu înlocuiește repo-ul și nu devine o bază de date separată.

Schimbările cu impact operațional care elimină nume sau schimbă semantica serviciilor locale se fac prin Work Order (WO), nu prin ștergere directă din UI. WO-ul rămâne în git, exprimă intenția operațională și trebuie dus până la capăt înainte să modifice registrul.

Endpoint-uri publice:

- `/` — pagina de login/aplicație, fără date de host până la autentificare
- `/api/session` — status boolean al sesiunii
- `/api/login`
- `/api/logout`

Healthcheck-ul `/healthz` este disponibil doar pe backend-ul local (`127.0.0.1:8088`). Vhost-ul nginx nu îl expune.

Endpoint-uri cu OTP:

- `/api/hosts`
- `/api/work-orders`
- `/api/ca/status`
- `/api/ca/certificates`
- `/download/hosts.yaml`
- `/download/local-hosts.tsv`
- `/download/monitoring.json`
- `/download/ca.crt`
- `POST /api/hosts/upsert`
- `POST /api/hosts/delete`
- `POST /api/work-orders/checklist`
- `POST /api/work-orders/confirm`
- `POST /api/render/local-hosts-tsv`

## Pornire locală

```bash
HOST_MANAGER_TOTP_SECRET="BASE32_SECRET_AICI" \
perl scripts/host_manager.pl --bind 127.0.0.1 --port 8088
```

Deschide:

```text
http://127.0.0.1:8088/
```

Implicit serverul ascultă doar pe loopback. Pe jumper, publicarea se face prin nginx, ca vhost separat, cu proxy către `127.0.0.1:8088`.

Vhost-ul implicit propus este:

```text
hosts.madagascar.xdev.ro
```

Configurațiile de deployment sunt în `deploy/jumper/`.

Checkout-ul de dezvoltare este local:

```text
/Users/bogdan/Documents/Workspaces/Xdev/Madagascar/LocalAuthority
```

Repo-ul canonic în GitPrep este:

```text
git@192.168.2.102:repositories/bogdan/LocalAuthority.git
http://192.168.2.102:3000/bogdan/LocalAuthority
```

Instanța runtime de pe jumper este instalată în `/usr/local/xdev-host-manager` și publicată prin:

```text
https://hosts.madagascar.xdev.ro/
```

Secretul TOTP nu este în repo. Pentru bootstrap, citește URI-ul root-only de pe jumper:

```bash
ssh jumper.madagascar.xdev.ro 'cat /etc/xdev/host-manager.totp-uri'
```

Codul aplicației se modifică local și se publică pe jumper cu:

```bash
scripts/deploy_to_jumper.sh
```

Scriptul de deploy nu copiază implicit `config/`, deoarece acesta conține date operaționale editabile de aplicația live. Folosește `--include-config` doar când vrei explicit să înlocuiești registrul runtime.

## OTP

`HOST_MANAGER_TOTP_SECRET` trebuie să fie un secret Base32 compatibil TOTP. Fără această variabilă, healthcheck-ul și pagina de login funcționează, dar login-ul, API-ul, download-urile și scrierile nu.

Secretul nu se comite în repo. Dacă avem nevoie de integrare cu un manager de secrete sau systemd environment file, se definește separat pe host.

## Flux

1. Hosturile se editează în aplicație sau direct în `config/hosts.yaml`.
2. Operatorii autentificați pot descărca `/download/hosts.yaml`, `/download/local-hosts.tsv` sau `/download/monitoring.json`.
3. Pentru DNS local, butonul `Write local-hosts.tsv` regenerează `config/local-hosts.tsv`.
4. Sincronizarea efectivă către jumper și as01 rămâne:

```bash
./scripts/sync_local_hosts.sh --apply --verify
```

## Work Orders

`config/work-orders.yaml` păstrează operațiuni care trebuie executate și confirmate înainte să atingă registrul.

Un WO nu înseamnă că numele nu mai este în uz. Înseamnă doar că vrem să ajungem acolo. Pentru retragerea unui nume, checklist-ul trebuie să acopere pașii reali: ștergerea vhostului, înlocuirea certificatelor publice cu certificate locale, reîncărcarea serviciilor, testarea accesului și verificarea că nu mai există consumatori.

În MVP, acțiunea suportată este:

```text
remove_name(host_id, name)
```

Confirmarea unui WO:

- cere tastarea exactă a ID-ului WO în interfață
- este blocată dacă există pași de checklist nemarcați `done`
- elimină numele declarate din `config/hosts.yaml`
- marchează WO-ul ca `confirmed`
- regenerează `config/local-hosts.tsv`
- nu rulează automat sync-ul către resolvere

După confirmare, operatorul verifică schimbarea în git și rulează explicit:

```bash
./scripts/sync_local_hosts.sh --apply --verify
```

Primul WO curent este pentru retragerea numelor locale `pmx.*`/`pbs.*` create istoric pentru vhosturi nginx cu certificate Let's Encrypt. Odată cu CA-ul local, aceste nume nu mai trebuie să existe ca vhosturi separate pentru interfețele Proxmox/PBS, dar rămân publicate până când checklist-ul operațional este complet și WO-ul este confirmat.

## Convenții de nume

`madagascar.xdev.ro` este domeniul implicit al rețelei interne. În `config/hosts.yaml` se declară doar numele canonice/FQDN-urile necesare.

Pentru orice nume `*.madagascar.xdev.ro`, aplicația derivă automat aliasul scurt prin eliminarea sufixului `.madagascar.xdev.ro`.

Exemple:

- `autonas01.madagascar.xdev.ro` produce automat aliasul `autonas01`
- `pmx.baobab.madagascar.xdev.ro` produce automat aliasul `pmx.baobab`

Aliasurile derivate nu se declară separat în `hosts.yaml`. Ele apar în API, monitoring export și `local-hosts.tsv` ca nume efective.

## Git și managementul cheilor

Varianta obligatorie pentru servicii automate este să citească `config/hosts.yaml` din git, nu să depindă de HTTP neautentificat. Serviciile care sincronizează DNS, monitorizare sau inventare primesc chei dedicate, cu acces minim.

Reguli:

- Fiecare host/serviciu automat are propria cheie SSH, fără reutilizare între roluri.
- Cheile de consum sunt read-only pentru repo.
- Cheile care pot scrie în repo sunt rare, separate și folosite doar de componenta de management.
- Cheile nu se comit în repo și nu se pun în `hosts.yaml`.
- Pentru deployment pe hosturi, se preferă chei restrânse la comanda necesară sau deploy keys read-only unde platforma git permite.
- Pull-ul automat trebuie să valideze fișierele înainte de aplicare; de exemplu `perl -c scripts/host_manager.pl` și `./scripts/sync_local_hosts.sh --verify` după generarea DNS.

Modelul recomandat:

```text
git repo
  config/hosts.yaml        sursă versionată
  config/local-hosts.tsv   manifest generat/versionat pentru DNS local
  config/work-orders.yaml  operațiuni confirmabile/versionate

jumper
  host-manager             editează working tree cu OTP
  sync_local_hosts.sh      aplică DNS după review/verificare

servicii consumatoare
  git pull read-only       citesc hosts.yaml/local-hosts.tsv
```

Pentru etapa MVP, aplicația nu face commit/push automat. După o modificare, schimbarea rămâne vizibilă în working tree și se comite explicit după review. Automatizarea commit/push poate fi adăugată ulterior, dar numai cu cheie separată și reguli clare de semnare/audit.

## Autoritate locală de certificate

Madagascar Local Authority include un helper OpenSSL pentru o autoritate locală de certificate pentru hosturi. Cheia privată CA nu este în git și nu este servită prin aplicație.

Locația implicită:

```text
/usr/local/xdev-host-manager/var/ca
```

Inițializare CA, pe jumper:

```bash
cd /usr/local/xdev-host-manager
sudo scripts/ca_manager.sh init
```

Semnare CSR pentru un host:

```bash
sudo scripts/ca_manager.sh sign-csr host-id /path/to/host.csr host.madagascar.xdev.ro host
```

Aplicația web, după OTP, poate afișa statusul CA, lista certificatelor emise și poate descărca certificatul public CA prin `/download/ca.crt`.

Reguli:

- Se semnează preferabil CSR-uri generate pe hosturi; cheia privată a hostului nu trebuie copiată în Madagascar Local Authority.
- CA private key rămâne local pe jumper și în afara git-ului.
- Endpoint-urile CA sunt în spatele OTP-ului.
- Automatizarea pentru emitere direct din UI se adaugă ulterior doar cu helper privilegiat și audit separat.

## Limitări MVP

- Parserul YAML acceptă schema strictă generată de aplicație, nu YAML arbitrar.
- Conflict engine-ul verifică doar consistența locală din `hosts.yaml`.
- DHCP, mDNS, `hosts-local.yaml` și `madagascar.json` sunt încă surse pentru audit manual sau pentru următorul collector.
