Medii de echipă
Împarte un mediu cu echipa — roluri, cont Linux și interval de porturi per membru, repository partajat, lock de build și moduri de izolare.
Mai multe persoane (și agenții lor) pot lucra în același mediu. Fiecare membru primește în mașină propria identitate, astfel încât credențialele unei persoane nu pot fi citite de alta, iar daemonul coordonează lucrurile care nu trebuie să ruleze de două ori.
Roluri
| Rol | Poate |
|---|---|
viewer | Să vadă mediul, membrii, porturile și evenimentele; să se atașeze. Nu i se provizionează un cont Linux pentru SSH. |
developer | Tot ce poate un viewer, plus să publice porturi până la authenticated, să listeze numele secretelor și să-și înregistreze cheia SSH. |
maintainer | În plus: pornire, oprire, arhivare, redenumire, schimbarea timpului de inactivitate, adăugare/eliminare de membri, publicare de porturi public, setare și ștergere de secrete, generare de tokenuri de înrolare (BYO). |
owner | În plus: distrugere, acordarea sau retragerea rolului owner. Un mediu păstrează mereu cel puțin un proprietar (409 last_owner). |
Cine creează mediul devine proprietarul lui. Proprietarii și administratorii organizației mediului au rol de owner; membrii obișnuiți ai organizației îl văd ca viewer. Oricine poate părăsi un mediu.
Adaugă un membru din hub (pagina mediului → Membri → e-mail + rol; persoana are nevoie de un cont codai cu acea adresă) sau cu POST /v1/environments/{id}/members și { "email": "ana@example.com", "role": "developer" }.
Identitate per membru
Când daemonul rulează ca serviciu de sistem cu root, în modul per-user (CODAI_SERVICE_SCOPE=system, implicit pe mașinile administrate), fiecare membru primește:
| Ce | Detalii |
|---|---|
| Cont Linux | u- urmat de primele 8 caractere hex din id-ul tău de utilizator — același pe fiecare mașină. Creat la prima folosire (useradd -m, grupul codai-dev, home 0750), afișat ca Utilizator Linux în hub. Comenzile de shell și terminalele rulează sub acest cont. |
| Identitate git | ~/.gitconfig cu numele și e-mailul membrului. |
| Worktree | ~/work/<slug-proiect> pe branch-ul implicit sau pe u/<utilizator> când acel branch e deja folosit de altcineva. Operațiile tale pe fișiere sunt limitate la worktree și la home. |
| Interval de porturi | Un bloc de 100 de porturi care începe la 30000, 30100, … Exportat comenzilor tale ca PORT (primul port) și CODAI_PORT_RANGE_START, CODAI_PORT_RANGE_END, CODAI_PORT_RANGE, ca serverele de dezvoltare a doi membri să nu se ciocnească. |
| Acces SSH | Lipește cheia publică la Cheia ta SSH (sau PUT /v1/environments/{id}/members/me/ssh-key). Daemonul o scrie în ~/.ssh/authorized_keys, iar hub-ul afișează Instalată. Viewerii nu sunt provizionați. |
Eliminarea unui membru
Când cineva este eliminat din mediu — sau retrogradat la viewer — daemonul îi dezactivează contul Linux în ordine, iar fiecare pas apare în evenimentele mediului (member.offboard.<pas>):
- locked — contul este blocat și expirat, iar cheia SSH este ștearsă;
- killed — sesiunile, procesele și containerul lui sunt oprite;
- archived — commit-urile nepublicate nicăieri și modificările necomise sunt salvate în repository-ul comun ca
refs/archive/<utilizator>/<moment>/<branch>(branch-ul lui nu este mutat; ref-urile de arhivă nu se șterg niciodată); - deleted — după 30 de zile, dacă nu a revenit, contul și home-ul sunt șterse.
Dacă este adăugat din nou în cele 30 de zile, contul este deblocat (restored), cu home-ul și worktree-urile intacte.
Dacă daemonul rulează fără root (identitate shared — implicită la o instalare BYO în scope de utilizator), toată lumea rulează sub același utilizator Unix, codaid status raportează identity_unsafe: true, iar agentul este instruit să trateze mașina ca nesigură pentru secrete. Folosește modul shared doar pe o mașină pe care lucrezi singur.
Repository partajat
Un proiect cu repo_url primește un singur repository bare partajat în /srv/codai/repos/<slug>.git (grupul codai-dev), adus o dată și folosit de worktree-ul fiecărui membru. Pentru a clona un repository privat, salvează un token ca secret de mediu CODAI_GIT_TOKEN (PUT /v1/environments/{id}/secrets/CODAI_GIT_TOKEN); daemonul îl transmite lui git printr-un helper askpass, niciodată în linia de comandă. Livrarea valorii secretului către daemon este în curs de lansare — până când gateway-ul tău o expune, daemonul clonează fără token (doar repository-uri publice).
Lock de build
Două build-uri simultane în același repository își strică reciproc rezultatele. O comandă de shell trimisă cu "lock": "build" ia un lock exclusiv la nivel de sistem de operare, fără așteptare:
- unul per repository per mediu în modul per-user (worktree-urile tuturor membrilor pentru același proiect împart un singur lock);
- eliberat automat dacă deținătorul se prăbușește;
- al doilea apelant primește imediat
{ "ok": false, "error": "lock_held: <holder>" }în loc să aștepte.
Lock-urile deținute apar în starea din relay (locks), pe cardul din desktop ca pictogramă de lacăt și în codaid status. Cine este atașat — oameni și agenți — apare în aceleași locuri.
Moduri de izolare
Alese per proiect (isolation), de cine administrează proiectul:
| Mod | Ce obții | Stare |
|---|---|---|
shared_vm (implicit) | O singură mașină; fiecare membru lucrează ca propriul utilizator Linux, cu propriul worktree și interval de porturi. | Disponibil |
container | Câte un container podman rootless per membru (codai-<slug>-<utilizator>), construit din devcontainer.json-ul repository-ului (.devcontainer/devcontainer.json sau .devcontainer.json; altfel mcr.microsoft.com/devcontainers/base:ubuntu-24.04), rulând sub uid-ul membrului, cu repository-ul comun și worktree-ul montate la căile lor din host, pe rețeaua host-ului cu intervalul de porturi al membrului. Shell-urile și terminalele rulează în container; operațiile pe fișiere rămân pe calea din host. | Live (daemon per-user + podman) |
vm_per_dev | Câte un mediu per dezvoltator, fixat pe el (for_user_id). Crearea unui al doilea răspunde 409 already_has_env cu id-ul de refolosit; astfel de medii au exact un membru. | Disponibil |
Câmpuri devcontainer.json suportate în modul container: image, build.{dockerfile,context,args,target}, forwardPorts, containerEnv, remoteEnv, containerUser, remoteUser, postCreateCommand (o singură dată), postStartCommand, mounts, runArgs, workspaceFolder, overrideCommand. Docker Compose nu este suportat.
Limite. Fiecare container de membru poate folosi toate CPU-urile mașinii, dar nu mai mult (--cpus), 75 % din RAM fără swap suplimentar și 4096 de procese; rulează cu no-new-privileges și cu toate capabilitățile eliminate, cu excepția CHOWN, DAC_OVERRIDE, FOWNER, SETUID, SETGID, KILL și NET_BIND_SERVICE. Dacă mașina nu delegă controlerele cgroup de CPU/memorie, containerul pornește fără limita de CPU/memorie, iar daemonul înregistrează un avertisment.
Lista permisă pentru runArgs. Sunt acceptate doar --add-host, -e/--env, --shm-size, --init și --label. Orice altceva — de exemplu --privileged, --network, --pid, --ipc, --cap-add, --security-opt, --device, --user — oprește pornirea containerului cu o eroare care numește flag-ul; elimină-l din runArgs. mounts și -v pot indica doar în worktree-ul sau home-ul tău (sau un volum numit ori tmpfs).
În hub, proiectele vm_per_dev grupează mediile pe dezvoltator (Mașina ta, Mașina lui …), iar fiecare dezvoltator își creează propriul mediu din pagina proiectului.
Ultima actualizare:
Porturi și preview-uri
Ajungi la un server de dezvoltare din mediu printr-un URL de preview sau o redirecționare locală de port și decizi cine îl poate deschide.
Facturare
Mediile administrate se taxează din portofel pe secundă de rulare și pe GB-lună de disc păstrat, în regim fail-closed; propriile servere sunt gratuite.