Sviluppo#
Comandi#
make build # bin/manent (client) e bin/manent-server con l'interfaccia web (NOUI=1 la salta)
make web # interfaccia web in internal/webui/dist (Node >= 20 o un container node:22)
make web-dev # interfaccia web su http://127.0.0.1:5173 contro un manent locale
make web-test # tipi, test dei componenti (Vitest) e allineamento con api/openapi.yaml
make web-api # rigenera i tipi TypeScript da api/openapi.yaml
make plugins # plugin esterni in bin/
make test # go test ./... (SQLite)
make test-postgres # gli stessi test su Postgres (avvia un container se serve)
make test-e2e # plugin remote-copy contro un server SSH reale in Docker
make test-load # carico e caos: più worker, uno cade a metà
make test-usecases # casi d'uso end-to-end su Docker Compose (vedi Casi d'uso)
make image # immagine container
make lint # gofmt + go vet
make fmt # gofmt -w
make proto # rigenera il codice gRPC dei plugin esterni
make docs # sito della documentazione in docs/site
make docs-serve # anteprima con ricarica automatica su http://<host>:8000/manent/ (DOCS_ADDR per cambiarlo)
make clean # rimuove binari, directory di lavoro, database SQLite e sito generato
Un singolo test:
make proto richiede protoc, protoc-gen-go e protoc-gen-go-grpc:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Test#
- Engine: i test avviano un DBOS reale su SQLite in una directory temporanea. Con
MANENT_TEST_DATABASE_URL(un server Postgres su cui l'utente può creare database) ogni test usa invece un database Postgres creato per lui ed eliminato alla fine (internal/testdb):make test-postgreslo fa con un container.scaling_test.goavvia più worker sullo stesso database per verificare la recovery perexecutor_id, la serializzazione per ambiente e l'assenza di doppi deploy dalle schedule. Usano unSchedulePollIntervalbasso: con il default di 30 secondi una nuova schedule partirebbe solo dopo il ricaricamento successivo. - Recovery e aggiornamenti:
recovery_test.gosimula la caduta di un worker (arresto non registrato) e verifica la recovery automatica e manuale, il rifiuto di un worker attivo, la migrazione dei workflow a una nuova versione e il drain.load_test.go(make test-load,MANENT_TEST_LOAD=1) accoda molti deploy su tre worker e ne fa cadere uno mentre esegue: tutti i deploy devono concludersi, mai due insieme nello stesso ambiente. - Casi d'uso:
test/usecasesavvia API, worker, client e target SSH su Docker Compose e percorre deploy, fallimenti, rollback e rilasci a ondate. Vedi Casi d'uso. - Interfaccia web: Vitest e Testing Library verificano le viste con un'API finta costruita sui tipi OpenAPI (
web/src/test);internal/webuile intestazioni di sicurezza e il fallback per il routing lato client;internal/api/openapi_test.gocheapi/openapi.yamldescriva esattamente le rotte del server. Playwright (web/e2e) gira in UC8 contro il laboratorio, con un identity provider OIDC di prova e axe per l'accessibilità. - SSH reale:
plugins/remotecopy/e2e_test.gogira solo conMANENT_TEST_SSH_ADDR;scripts/e2e-ssh.shavvia un sshd Debian in Docker (test/e2e/sshd) e verifica layout releases, pulizia, rollback e checksum. - Plugin esterni: i test di
internal/extplugincompilanotestdata/fakeplugine avviano processi reali. Verificano segreti, isolamento dell'ambiente, inoltro dei log, riavvio dopo un crash e verifica dello sha256. - Plugin:
remotecopysostituisce SSH con le interfacceDialereSession. - Callback: i test usano un server
httpteste verificano le quattro modalità di autenticazione e la policy sugli URL. - Accesso:
internal/authverifica i token OIDC contro un identity provider finto (discovery, JWKS e JWT firmati in memoria);internal/authzpermessi e audit su un servizio finto;internal/apile risposte 401/403. - Vault: i test usano un server
httptestche simula KV v1/v2, il login AppRole e la revoca del token. - Rollback:
internal/engine/rollback_test.goverifica ordine di checkpoint e compensazioni, arresto alla prima compensazione fallita e dry-run;internal/rollbackle policy per tipo di artefatto.
CI e rilasci#
.github/workflows/ci.yml esegue su ogni push e pull request: lint e go mod tidy, test su SQLite, test su Postgres con carico e caos, test SSH end-to-end, build del sito, helm lint e build dell'immagine.
Un rilascio parte da un tag vX.Y.Z (.github/workflows/release.yml):
- spostare la sezione
UnreleaseddiCHANGELOG.mdin## [X.Y.Z] - AAAA-MM-GGe aggiornareappVersionindeploy/helm/manent/Chart.yaml; git tag vX.Y.Z && git push --tags;- GoReleaser (
.goreleaser.yaml) compila i binari, crea archivi con SBOM, firma i checksum e l'immagine con cosign (keyless) e pubblica il rilascio con le note del CHANGELOG (scripts/release-notes.sh).
Cosa è considerato incompatibile è descritto in Versioni e aggiornamenti.
Convenzioni#
- Ogni servizio è definito tramite interfacce, per facilitare mock e test.
- Ogni componente riceve il logger per iniezione. I log arrivano sia al log applicativo sia al SIEM come
rfc5424.Message. - I commenti nel codice sono in inglese, concisi ma completi.
internal/appè l'unico punto di composizione: i nuovi plugin interni si registrano inapp.NewPlugins, i nuovi step inapp.NewSteps.- Un nuovo step che deve funzionare in dry-run implementa
pipeline.DryRunner. Altrimenti viene saltato. - Un nuovo step che modifica gli ambienti implementa
pipeline.Compensator(e, se deve registrare lo stato precedente,pipeline.Checkpointer), così il rollback può annullarlo. - Un errore che un nuovo tentativo non può risolvere (policy, validazione) va marcato con
pipeline.Permanent: lo step fallisce subito senza i retry. - Un nuovo provider di segreti implementa
secrets.Providere si registra per schema inapp.NewSecretProvider. - Un nuovo locator di rollback implementa
plugin.ReleaseLocatore si registra inapp.NewLocators. - I nomi dei workflow DBOS (
manent.deploy,manent.scheduled-deploy,manent.approval) non vanno cambiati. Una modifica incompatibile alla struttura di un workflow (step in ordine diverso, input diverso) richiede una nuova versione dei workflow (app.version), da segnalare nel CHANGELOG. - Nel codice degli step i log vanno emessi con il context dello step (
InfoContext(ctx, ...)): solo così arrivano al log del deploy. - La documentazione in
docs/contentva aggiornata insieme alle funzionalità. Vedidocs/README.mdper la struttura del sito.
Struttura del repository#
cmd/manent/ client (solo API)
cmd/manent-server/ server: API, worker, admin
cmd/manent-plugin-remote-copy/ remote-copy come plugin esterno
deploy/helm/manent/ chart Helm
deploy/systemd/ unità systemd
scripts/ test end-to-end e note di rilascio
test/e2e/ immagini per i test end-to-end
internal/ motore (non importabile da fuori)
pkg/plugin/ contratto pubblico dei plugin
pkg/plugin/external/ SDK e protocollo gRPC dei plugin esterni
plugins/remotecopy/ plugin di riferimento
api/openapi.yaml contratto dell'API HTTP
web/ interfaccia web (React, TypeScript, Vite)
internal/webui/ incorpora e serve la build di web/
configs/ configurazione d'esempio
examples/ descrittori e configurazioni di ambiente d'esempio
docs/ questo sito