Compare commits

..
25 Commits
Author SHA1 Message Date
Fabio 34a5d4177b Merge lavoro/cartella-progetti 2026-10-13 09:53:14 +02:00
FabioandClaude Opus 5.5 0705b6c0e7 progetti.sh e Claude chiedono dove scaricare, niente piu' ~/Work/workspace/oto
La cartella dei progetti era fissata in comune.sh su ~/Work/workspace/oto,
cioe' la cartella di chi ha scritto gli script, e il CLAUDE.md diceva di
clonare li' anche questo repository. Adesso la sceglie la persona:
progetti.sh la vuole con --in (o CARTELLA_PROGETTI), la chiede se puo' e
altrimenti si ferma; il CLAUDE.md ha la regola di chiederla sempre prima
di scaricare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:48:41 +02:00
Fabio 042c550443 Merge lavoro/onboard-mac 2026-10-12 11:57:05 +02:00
FabioandClaude Opus 5.5 696b28083e onboard su Mac: brew nel PATH, e OpenVPN Connect lo installa la persona
Note di Giorgio, primo onboard su Mac: dopo Homebrew brew non e' nel PATH
di un terminale nuovo (aws non si trova), e brew install --cask
openvpn-connect chiede la password del Mac. comune.sh ora trova brew da
solo in /opt/homebrew o /usr/local.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:54:45 +02:00
Fabio e51ff0cf4f Merge lavoro/report-analisi 2026-10-11 10:32:41 +02:00
FabioandClaude Opus 5.5 eb68d8930e onboard: niente piu' esiti verdi su passi falliti, git e AWS verificati davvero
- configura.sh e progetti.sh escono 1 se un passo non riesce (scrittura di
  ~/.ssh/config, chiave SSH, clone, chiave AWS), e lo dicono in rosso;
- git: per l'indirizzo di Gitea si usa solo il gestore "store", e un token
  vecchio rimasto in ~/.git-credentials si sostituisce (prima si aggiungeva
  solo se mancava: API buona e git clone rotto). verifica.sh chiede a git la
  credenziale che userebbe davvero, invece di accontentarsi di un gestore
  qualsiasi;
- AWS: la chiave si controlla PRIMA di salvarla, e deve essere l'utente della
  persona nell'account di OTO (ARN completo, non solo il nome). Senza Gitea il
  passo si salta e verifica.sh non da' piu' verde a una chiave qualsiasi.
  Avviso se AWS_PROFILE o AWS_ACCESS_KEY_ID... fanno usare un'altra chiave;
- API di Gitea: codice HTTP controllato, "Gitea non risponde" distinto da
  "token non valido", elenco dei progetti interrotto solo su una pagina vuota
  vera; token passato a curl da stdin; JSON letto anche con gli spazi;
- progetti.sh: nomi confrontati in modo esatto, accetta organizzazione/nome
  e dice quando un nome corto e' ambiguo;
- la chiave ~/.ssh/oto_ed25519 viene collegata anche ai nomi che cercano i
  deploy dei progetti (oto_staging_ed25519, oto_production_ed25519): su un
  PC preparato da qui il primo deploy si fermava con "Chiave privata non
  trovata";
- verifica.sh --senza-vpn, per chi non ha la VPN: staging giallo e non rosso.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:27:17 +02:00
FabioandClaude Opus 5.5 e544e90661 Merge lavoro/onboard-known-hosts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:49:20 +02:00
FabioandClaude Opus 5.5 b83fc9883d onboard: le chiavi dei server in known_hosts, e verifica dice perche' non entri
Marco Laterza, amministratore, si e' visto dire "produzione: non entri
(normale se non hai il ruolo di rilascio...)" con la chiave gia' sul
server: al suo PC mancava la chiave host della macchina nuova, e con
BatchMode=yes ssh rifiuta un host sconosciuto senza provare la chiave.

configura.sh scrive in ~/.ssh/known_hosts le chiavi di server.known_hosts,
lette sulle tre macchine l'08/10/2026, togliendo prima quelle vecchie per
gli stessi nomi. verifica.sh legge l'errore di ssh: giallo solo se il
server rifiuta la chiave personale, rosso con il rimedio per chiave host
mancante o cambiata e per il blocco dopo troppi tentativi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:47:10 +02:00
Fabio 2a4dbf3ad2 Merge lavoro/credenziali-su-lastpass 2026-10-07 23:39:45 +02:00
FabioandClaude Opus 5.5 6fa20345b1 onboard: la scheda LastPass della VPN e' OTO > VPN HK nome.cognome
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:37:23 +02:00
FabioandClaude Opus 5.5 d5e2e530e8 onboard: password Gitea e chiave AWS dalle schede LastPass, non dalla mail
La mail "I tuoi accessi OTO" non ha piu' password. configura.sh manda a
cercarle per nome: "Gitea > nome.cognome" (campo Password) e
"AWS > Nome Cognome" (Access key ID e Secret nel campo di testo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:32:20 +02:00
Fabio 497df7eeb0 Merge lavoro/token-organizzazione 2026-10-07 22:55:25 +02:00
FabioandClaude Opus 5.5 edc5d4e4b3 configura: token Gitea con write:organization, e rinnovo di quelli vecchi
Dal 07/10/2026 i progetti nascono nell'organizzazione oto, e crearli vuole
write:organization (prima read:organization). Un token salvato senza quello
scope viene riconosciuto (Gitea risponde 403 a una creazione volutamente
incompleta, 422 se lo scope c'e', e non crea niente), messo da parte e
sostituito.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:55:25 +02:00
FabioandClaude Opus 5.5 fb523fd5e1 Merge lavoro/mfa-da-admin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:33:59 +02:00
FabioandClaude Opus 5.5 70d723f613 onboard: niente console AWS il primo giorno, e il comando con il percorso vero
L'MFA lo attiva chi amministra, quindi la persona non entra ne' in AWS ne'
in Gitea dal browser. Per configura.sh Claude le da' il comando completo,
con il percorso della cartella su quel PC: la pagina non lo scrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:33:59 +02:00
FabioandClaude Opus 5.5 c55f3052e7 Merge lavoro/via-domanda-caso
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:30:35 +02:00
FabioandClaude Opus 5.5 bc3d2cf09b onboard: niente domanda sul lavoro che fa, la VPN la dice la nota LastPass
Lo decide gia' chi amministra: chi ha la mail fa tutti i passi, e la VPN
serve solo se su LastPass c'e' la nota VPN. OpenVPN Connect si installa a
quel passo, solo a chi serve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:30:35 +02:00
FabioandClaude Opus 5.5 6365654278 Merge lavoro/vpn-e-mail
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:05:31 +02:00
FabioandClaude Opus 5.5 5a2cd26f52 onboard: accessi nella mail, chiave AWS e VPN su LastPass
Utenti e password arrivano nella mail "I tuoi accessi OTO", pronti da
copiare; la chiave AWS e la VPN (file .ovpn e credenziali) stanno in note
LastPass. Claude installa OpenVPN Connect e guida la persona a scaricare
il file e accendere la VPN. Alla fine lei risponde alla mail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:05:31 +02:00
FabioandClaude Opus 5.5 d71753a5da Merge lavoro/password-definitive
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:02:22 +02:00
FabioandClaude Opus 5.5 194a73b790 password: quella del messaggio di benvenuto e' gia' la definitiva
Da oggi nuova-persona.sh non obbliga piu' a cambiare le password di AWS e
Gitea al primo accesso. configura.sh chiede la password Gitea della nota
LastPass, e il passo Gitea nel browser sparisce. Il 403 resta gestito per
chi e' stato creato prima. Nel README la frase nuova per Claude.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:02:22 +02:00
FabioandClaude Opus 5.5 265f0c151e Merge lavoro/chiave-aws-da-admin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:27:10 +02:00
FabioandClaude Opus 5.5 0ab5518a36 configura.sh: la chiave AWS si copia dal messaggio di benvenuto su LastPass
La crea chi amministra insieme all'utente. La strada della console resta
come riserva, per chi e' arrivato prima o l'ha persa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:26:34 +02:00
FabioandClaude Opus 5.5 c8d065e32c Merge lavoro/produzione-nuova
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:02:01 +02:00
FabioandClaude Opus 5.5 608438323f configura.sh e verifica.sh: anche la produzione nuova
In ~/.ssh/config c'era solo oto-production-old. Adesso c'e' anche
oto-production (10.110.137.20, dietro VPN), con il suo utente
admin.produzione: l'utente non e' piu' uno solo per tutti i server.
verifica.sh controlla tutte e due le produzioni, un tentativo per macchina.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:59:58 +02:00
7 changed files with 597 additions and 184 deletions
+100 -45
View File
@@ -2,10 +2,14 @@
Chi ti parla è una persona **nuova in OTO**, spesso non tecnica, al primo Chi ti parla è una persona **nuova in OTO**, spesso non tecnica, al primo
giorno. Ti ha scritto qualcosa come «prepara il mio PC per OTO» e ha in mano giorno. Ti ha scritto qualcosa come «prepara il mio PC per OTO» e ha in mano
solo le password provvisorie che le ha mandato l'amministratore. **Il lavoro la mail *I tuoi accessi OTO* che le ha mandato chi amministra (link,
utente, email, la frase per te, **nessuna password**) e, su LastPass, due
schede condivise con lei: `AWS > Nome Cognome` (console, MFA e, nel campo di
testo, la chiave di accesso) e `Gitea > nome.cognome` (password Gitea), più
la scheda `OTO > VPN HK nome.cognome` se le serve la VPN. **Il lavoro
lo fai tu**: installi i programmi, lanci i controlli, le dici cosa cliccare. lo fai tu**: installi i programmi, lanci i controlli, le dici cosa cliccare.
Lei fa solo quello che tu non puoi fare: i login nel browser, e scrivere i Lei fa solo quello che tu non puoi fare: scrivere i propri segreti nel
propri segreti nel terminale. Parla semplice, un passo alla volta, e controlla terminale e, se le serve, accendere la VPN. Parla semplice, un passo alla volta, e controlla
ogni passo prima del successivo. ogni passo prima del successivo.
La spiegazione per le persone sta in La spiegazione per le persone sta in
@@ -19,7 +23,13 @@ La spiegazione per le persone sta in
`configura.sh` nel terminale, con l'input nascosto. `configura.sh` nel terminale, con l'input nascosto.
2. **`configura.sh` lo lancia la persona**, in un terminale suo: tu non puoi 2. **`configura.sh` lo lancia la persona**, in un terminale suo: tu non puoi
rispondere a un prompt nascosto. Diglielo con le parole giuste per dove rispondere a un prompt nascosto. Diglielo con le parole giuste per dove
lavora (vedi sotto). Tu lanci tutto il resto: installazioni, `verifica.sh`, lavora (vedi sotto), e **dalle il comando completo, da copiare così
com'è**: `cd` nel percorso vero della cartella su quel PC (quello in cui
l'hai scaricata, che conosci solo tu: la pagina per le persone non lo
scrive apposta) e `./configura.sh`, in un blocco di codice, per esempio
`cd "/c/Users/mario/oto/_OTO_IT_onboard" && ./configura.sh`.
Su Windows il percorso va nella forma di Git Bash (`/c/Users/...`), non
`C:\...`. Tu lanci tutto il resto: installazioni, `verifica.sh`,
`progetti.sh`, i comandi di sola lettura. `progetti.sh`, i comandi di sola lettura.
3. **Non creare accessi e non chiederli.** Utenti AWS e Gitea, VPN, chiavi 3. **Non creare accessi e non chiederli.** Utenti AWS e Gitea, VPN, chiavi
sui server li crea un amministratore. Se manca qualcosa, dillo con sui server li crea un amministratore. Se manca qualcosa, dillo con
@@ -29,7 +39,15 @@ La spiegazione per le persone sta in
Lo dici e prosegui. Lo dici e prosegui.
5. **Non copiare file da altri PC** e non proporlo: se a un progetto manca un 5. **Non copiare file da altri PC** e non proporlo: se a un progetto manca un
segreto, va messo su AWS SSM da un amministratore. segreto, va messo su AWS SSM da un amministratore.
6. **Ogni volta che le chiedi qualcosa, le dici dove lo trova o dove lo 6. **Dove scaricare lo chiedi sempre, prima di scaricare.** Questo
repository e i progetti vanno nella cartella che sceglie la persona, non
in una che decidi tu: non esiste un posto di default (fino al 13/10/2026
le istruzioni dicevano `~/Work/workspace/oto`, che era la cartella di chi
le ha scritte). Chiedile in quale cartella vuole i progetti, proponendo
al massimo un esempio (sotto la sua cartella utente), e usa quella. Se
l'ha già scelta per questo repository, chiedile se i progetti vanno
accanto a lui, e non darlo per scontato.
7. **Ogni volta che le chiedi qualcosa, le dici dove lo trova o dove lo
crea.** Non "inserisci la chiave AWS", ma "la crei nella console AWS: il crea.** Non "inserisci la chiave AWS", ma "la crei nella console AWS: il
tuo nome in alto a destra → Security credentials → …". Indirizzo, menu e tuo nome in alto a destra → Security credentials → …". Indirizzo, menu e
pulsante, con i nomi come li vede sullo schermo (in inglese, se la pagina pulsante, con i nomi come li vede sullo schermo (in inglese, se la pagina
@@ -42,14 +60,13 @@ La spiegazione per le persone sta in
| Cosa | Dove lo trova o lo crea | | Cosa | Dove lo trova o lo crea |
|---|---| |---|---|
| Indirizzo, utente e password provvisoria di AWS e di Gitea | nel **messaggio di benvenuto** che le ha mandato chi amministra. Se non ce l'ha, lo chiede a lui: tu non puoi recuperarlo | | Utente Gitea ed email | nella **mail *I tuoi accessi OTO*** che le ha mandato chi amministra: righe già pronte da copiare. Se non ce l'ha, risponde a quella mail o lo chiede a lui: tu non puoi recuperarlo |
| Password nuova di AWS | la sceglie lei: AWS la chiede subito dopo il primo login, nella pagina che si apre da sola | | Password Gitea | su **LastPass**, scheda **`Gitea > nome.cognome`** (per esempio `Gitea > sara.locatelli`), campo *Password*. Nella mail non c'è, apposta |
| Codice dal telefono (MFA) di AWS | console AWS → il suo nome in alto a destra → *Security credentials* → riquadro *Multi-factor authentication (MFA)* → *Assign MFA device* → *Authenticator app*. Serve un'app di autenticazione sul telefono (Google Authenticator, Microsoft Authenticator o simili): se non ce l'ha, prima la installa dallo store | | Indirizzo, utente, password e codice a due fattori della console AWS | su **LastPass**, scheda **`AWS > Nome Cognome`** (nome per esteso: `AWS > Sara Locatelli`). Il primo giorno non servono |
| Chiave di accesso AWS (*Access key ID* e *Secret access key*) | console AWS → il suo nome in alto a destra → *Security credentials* → riquadro *Access keys* → *Create access key* → *Command Line Interface (CLI)* → spunta la conferma → *Next* → *Create access key*. I due pezzi sono nella pagina *Retrieve access keys*; la Secret si vede con *Show*, una volta sola. Se l'ha chiusa: cancella quella chiave dallo stesso riquadro e ne crea un'altra | | Chiave di accesso AWS (*Access key ID* e *Secret access key*) | su **LastPass**, scheda **`AWS > Nome Cognome`**, nel **campo di testo**: due righe, *Access key ID* (inizia con `AKIA`) e *Secret access key*. Nella mail non c'è, apposta: la crea chi amministra insieme all'utente. Solo se lì non c'è (è arrivata prima, o la chiave è stata cancellata), la crea lei: console AWS → il suo nome in alto a destra → *Security credentials* → riquadro *Access keys* → *Create access key* → *Command Line Interface (CLI)* → spunta la conferma → *Next* → *Create access key*. I due pezzi sono nella pagina *Retrieve access keys*; la Secret si vede con *Show*, una volta sola. Se l'ha chiusa: cancella quella chiave dallo stesso riquadro e ne crea un'altra |
| Password nuova di Gitea | la sceglie lei: `https://git.oto-farm.com` → *Sign in* in alto a destra → utente e password provvisoria; Gitea chiede subito quella nuova | | Utente Gitea | è nella mail (`nome.cognome`); su Gitea lo vede in alto a destra, cliccando l'icona del profilo |
| Utente Gitea | è quello del messaggio di benvenuto (`nome.cognome`); su Gitea lo vede in alto a destra, cliccando l'icona del profilo |
| Email di lavoro | il suo indirizzo `@oto.agency` | | Email di lavoro | il suo indirizzo `@oto.agency` |
| File della VPN | lo manda chi amministra, che lo riceve dal fornitore. Il programma da installare dipende dal file: `.ovpn` → OpenVPN Connect, `.conf` → WireGuard. Se il file non le è arrivato, lo chiede a chi amministra | | File e credenziali della VPN | nella **scheda LastPass `OTO > VPN HK nome.cognome`** condivisa da chi amministra: il file `.ovpn` è allegato alla scheda (*Attachments* → si scarica, finisce in *Download*), utente e password della VPN sono scritti nella scheda. Il programma è **OpenVPN Connect**, lo installi tu. Se la scheda non c'è, lo chiede a chi amministra |
| Password del Mac (per Homebrew) | è quella con cui accende il Mac | | Password del Mac (per Homebrew) | è quella con cui accende il Mac |
| Accesso a un progetto che non vede su Gitea | lo dà chi amministra: dille il nome del progetto da chiedere | | Accesso a un progetto che non vede su Gitea | lo dà chi amministra: dille il nome del progetto da chiedere |
@@ -65,18 +82,18 @@ La spiegazione per le persone sta in
Capisci da solo se sei su Windows o su Mac (`uname -s`, `$OS`): non chiederlo. Capisci da solo se sei su Windows o su Mac (`uname -s`, `$OS`): non chiederlo.
## Prima domanda: qual è il suo caso ## Non le chiedi che lavoro fa
- **modifica testi e immagini solo dal pannello** (o dall'area di Lo ha già deciso chi amministra (deciso il 07/10/2026): se la persona ha la
amministrazione di WordPress/Drupal): non le serve niente di questo mail, le servono tutti i passi; se su LastPass ha anche la scheda `OTO > VPN HK nome.cognome`, le
repository. Diglielo e fermati. serve anche la VPN. Chi lavora solo dal pannello del sito non riceve la mail
- **crea o modifica pagine con Claude, senza scrivere codice**: tutti i passi e non arriva qui. Alla VPN (passo 5) le chiedi soltanto se fra le schede
**tranne VPN** (passo 5). `verifica.sh` segnerà rossi VPN e staging: dille LastPass condivise con lei c'è `OTO > VPN HK nome.cognome`: se no, salti il
che per lei è normale. passo, e lanci `./verifica.sh --senza-vpn`: staging non raggiungibile
- **sviluppa**: tutti i passi. diventa giallo invece che rosso, e il risultato può essere tutto a posto.
Con chi non sviluppa niente gergo: se una parola tecnica serve (terminale, Niente gergo: se una parola tecnica serve (terminale, token, push),
token, push), spiegala in una riga la prima volta. spiegala in una riga la prima volta.
## L'ordine ## L'ordine
@@ -90,42 +107,70 @@ token, push), spiegala in una riga la prima volta.
- **Mac**: prima Homebrew. Il suo installatore chiede la password del Mac, - **Mac**: prima Homebrew. Il suo installatore chiede la password del Mac,
quindi quel comando lo lancia la persona nel Terminale: quindi quel comando lo lancia la persona nel Terminale:
`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`.
Poi tu: `brew install git awscli` e `brew install --cask docker`. **Homebrew non si mette da solo nel `PATH`** (sui Mac Apple Silicon sta
in `/opt/homebrew`): senza, in un terminale nuovo `brew` e `aws` non si
trovano. Lo aggiungi tu, una volta:
`echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile`
(su un Mac Intel sta in `/usr/local` e il passo non serve). Poi tu:
`eval "$(/opt/homebrew/bin/brew shellenv)" && brew install git awscli`
e `brew install --cask docker`. Se un'installazione `--cask` chiede la
password del Mac, la lancia la persona nel Terminale. Gli script di
questo repository trovano `brew` anche senza il `PATH` sistemato, il
terminale della persona no.
- Docker Desktop va **aperto una volta** a mano e le condizioni accettate: - Docker Desktop va **aperto una volta** a mano e le condizioni accettate:
finché non lo si fa, `docker info` non risponde. finché non lo si fa, `docker info` non risponde.
2. **Questo repository sul PC**, se ci stai parlando da un link e non da 2. **Questo repository sul PC**, se ci stai parlando da un link e non da
dentro la cartella: `git clone https://git.oto-farm.com/admin/_OTO_IT_onboard.git dentro la cartella. Prima le chiedi dove metterlo (regola 6), poi:
~/Work/workspace/oto/_OTO_IT_onboard` (è pubblico, non ha segreti) e da lì `git clone https://git.oto-farm.com/admin/_OTO_IT_onboard.git
"<cartella scelta>/_OTO_IT_onboard"` (è pubblico, non ha segreti) e da lì
continui. continui.
3. **I login nel browser**, li fa lei: 3. **Niente login su AWS né su Gitea nel browser** (deciso il 07/10/2026):
- **AWS**: entrare dall'indirizzo del messaggio di benvenuto (*IAM user*, le password sono già le definitive e l'MFA di AWS lo attiva chi
utente e password provvisoria), scegliere la password nuova, attivare amministra, con il seme nella scheda LastPass `AWS > Nome Cognome`. La
l'MFA e creare la chiave di accesso. I percorsi esatti sono nella tabella chiave di accesso **non** la crea: è già nel campo di testo di quella
qui sopra: dàglieli un passo alla volta. **Lasciare aperta la pagina scheda. Solo se lì non c'è, la crea dalla console AWS (percorso nella
della chiave**: la parte segreta si vede una volta sola. tabella qui sopra), entrando con utente, password e codice a due fattori
- **Gitea** (`https://git.oto-farm.com`, *Sign in* in alto a destra): della stessa scheda.
entrare con la password provvisoria e sceglierne una nuova. Nient'altro:
il token lo crea lo script.
4. **`./configura.sh`**, nel terminale della persona. Chiede utente e 4. **`./configura.sh`**, nel terminale della persona. Chiede utente e
password di Gitea e poi i due pezzi della chiave AWS; crea l'accesso a password di Gitea (l'utente dalla mail, la password dalla scheda
`Gitea > nome.cognome`) e poi i due pezzi della chiave AWS, che lei copia
dal campo di testo della scheda `AWS > Nome Cognome`; crea l'accesso a
Gitea, configura git, genera la chiave SSH e la carica sul suo profilo Gitea, configura git, genera la chiave SSH e la carica sul suo profilo
Gitea (da lì la prende l'amministratore: **non va mandata a nessuno**), Gitea (da lì la prende l'amministratore: **non va mandata a nessuno**),
scrive i nomi dei server in `~/.ssh/config`. Poi fa chiudere la pagina di scrive i nomi dei server in `~/.ssh/config` e le loro chiavi in
AWS. Gitea viene prima apposta: è lui a dire chi è la persona. Se sul PC `~/.ssh/known_hosts` (da `server.known_hosts`). La chiave la crea come
`~/.ssh/oto_ed25519` e la collega anche ai due nomi con cui la cercano i
deploy dei progetti, `oto_staging_ed25519` e `oto_production_ed25519`
(un file che c'è già con quel nome non lo tocca). Esce con errore se un
passo non è riuscito, e lo dice in rosso: allora non si va avanti. Gitea viene prima apposta: è lui a dire chi è la persona. Se sul PC
c'è già una chiave AWS **di un altro** (rimasta da chi lo usava, o copiata c'è già una chiave AWS **di un altro** (rimasta da chi lo usava, o copiata
da un collega), lo script lo dice e chiede la sua: dille di avvisare da un collega), lo script lo dice e chiede la sua: dille di avvisare
l'amministratore, perché quella chiave va disattivata. Una chiave altrui l'amministratore, perché quella chiave va disattivata. Una chiave altrui
non va mai tenuta "intanto che funziona": tutto quello che la persona fa non va mai tenuta "intanto che funziona": tutto quello che la persona fa
su AWS risulterebbe fatto dall'altro. su AWS risulterebbe fatto dall'altro.
5. **VPN** (solo chi sviluppa): installare il programma giusto per il file 5. **VPN**, solo se su LastPass ha la scheda `OTO > VPN HK nome.cognome` (chiediglielo). Prima
(vedi tabella) e aprirci dentro il file che le ha mandato chi amministra. va installato OpenVPN Connect: su Windows lo installi tu,
6. **Dirlo all'amministratore**: «ho finito la configurazione». È il segnale `winget install -e --id OpenVPNTechnologies.OpenVPNConnect`; su Mac
`brew install --cask openvpn-connect` chiede la password del Mac (installa
un componente di sistema), quindi lo lancia la persona nel Terminale e tu
le dai il comando. Poi lei, un passo alla volta: apre la scheda VPN su LastPass e scarica il file
`.ovpn` allegato; apre OpenVPN Connect → *Upload File* (o *Import
Profile* → *File*) → *Browse* → il file in *Download*; scrive utente e
password della VPN dalla stessa scheda, spunta *Save password*, *Connect*.
È accesa quando l'interruttore diventa verde (*Connected*).
6. **Dirlo all'amministratore**: risponde alla mail *I tuoi accessi OTO*
scrivendo «ho finito la configurazione». È il segnale
per mettere la sua chiave SSH sui server; finché non lo fa, staging resta per mettere la sua chiave SSH sui server; finché non lo fa, staging resta
rosso. rosso.
7. **`./verifica.sh`**: tutto verde, o un elenco preciso di cosa manca e a chi 7. **`./verifica.sh`** (`--senza-vpn` se non ha la VPN): tutto verde, o un
chiederlo. elenco preciso di cosa manca e a chi chiederlo. Controlla anche che git
8. **`./progetti.sh`**: scarica i progetti che la persona vede su Gitea (lo entri su Gitea con il token giusto e che la chiave AWS sia la sua
lanci tu con i nomi: `./progetti.sh nome1 nome2`). Poi, in ogni progetto: nell'account di OTO, non solo un utente con lo stesso nome.
8. **`./progetti.sh`**: scarica i progetti che la persona vede su Gitea.
Prima le chiedi in quale cartella (regola 6), poi lo lanci tu con la
cartella e i nomi: `./progetti.sh --in "<cartella scelta>" nome1 nome2`.
Senza `--in` lo script non scarica niente: un posto di default non c'è
apposta. Poi, in ogni progetto:
`./start.sh` per i progetti con pannello, `bin/local-init.sh` per Drupal e `./start.sh` per i progetti con pannello, `bin/local-init.sh` per Drupal e
WordPress. Il resto lo spiega il `CLAUDE.md` di quel progetto. WordPress. Il resto lo spiega il `CLAUDE.md` di quel progetto.
@@ -139,4 +184,14 @@ Dillo alla persona, invece di farle scoprire un rosso inspiegabile:
correggerlo; correggerlo;
- **alcuni progetti non hanno ancora tutti i segreti su SSM**: in locale - **alcuni progetti non hanno ancora tutti i segreti su SSM**: in locale
qualcosa può mancare; qualcosa può mancare;
- la produzione nuova non esiste ancora: in `~/.ssh/config` c'è quella vecchia. - **le produzioni sono due** finché i siti non sono migrati tutti: in
`~/.ssh/config` ci sono `oto-production` (la macchina nuova, dietro la VPN
come staging, utente `admin.produzione`) e `oto-production-old` (quella
dove girano ancora i siti). Chi ha il ruolo di rilascio entra in tutte e
due; per gli altri sono gialle tutte e due, ed è normale. Giallo vuol
dire solo "il server non accetta la tua chiave": se una riga è rossa il
ruolo non c'entra, e `verifica.sh` dice cosa fare (di solito rilanciare
`configura.sh`, che registra le chiavi dei server). Se ssh chiede *Are you
sure you want to continue connecting?*, non far rispondere `yes` alla
cieca: le chiavi giuste sono in `server.known_hosts`, e le registra
`configura.sh`.
+10 -6
View File
@@ -6,14 +6,18 @@ scaricano i progetti stessi da AWS, con il tuo accesso personale.
## Come si usa ## Come si usa
1. Installa **Visual Studio Code** e, dentro, l'estensione **Claude Code** 1. Apri **Visual Studio Code** con l'estensione **Claude Code** (oppure
(oppure l'app **Claude**, scheda *Code*). Entra con l'invito di Claude. Cowork). Entra con l'invito di Claude.
2. Scrivi a Claude: 2. Scrivi a Claude:
> Prepara il mio PC per OTO: https://git.oto-farm.com/admin/_OTO_IT_onboard > Scarica il progetto https://git.oto-farm.com/admin/_OTO_IT_onboard e prepara il mio PC per OTO
Il resto lo fa Claude: installa i programmi e ti dice cosa cliccare. Tu fai i Il resto lo fa Claude: installa i programmi e ti dice cosa cliccare. Tu
login nel browser e scrivi le tue chiavi nel terminale quando te lo chiede. scrivi le tue chiavi nel terminale, con il comando che ti da' Claude.
L'utente e' nella mail *I tuoi accessi OTO* che ti ha mandato chi amministra;
password e chiavi su LastPass, nelle schede condivise con te:
`Gitea > nome.cognome` (password Gitea), `AWS > Nome Cognome` (chiave AWS nel
campo di testo) e, se ti serve, `OTO > VPN HK nome.cognome`.
## Una regola ## Una regola
@@ -29,7 +33,7 @@ La spiegazione completa è su
```bash ```bash
./configura.sh # chiede quello che serve, una cosa per volta ./configura.sh # chiede quello che serve, una cosa per volta
./verifica.sh # dice verde o rosso per ogni accesso ./verifica.sh # dice verde o rosso per ogni accesso
./progetti.sh # scarica i progetti a cui hai accesso ./progetti.sh # chiede dove, e scarica i progetti a cui hai accesso
``` ```
Si possono rilanciare quante volte si vuole: quello che è già a posto non Si possono rilanciare quante volte si vuole: quello che è già a posto non
+81 -15
View File
@@ -6,23 +6,32 @@
GITEA_URL="https://git.oto-farm.com" GITEA_URL="https://git.oto-farm.com"
GITEA_HOST="git.oto-farm.com" GITEA_HOST="git.oto-farm.com"
AWS_REGIONE="eu-central-1" AWS_REGIONE="eu-central-1"
AWS_CONSOLE="https://170187898933.signin.aws.amazon.com/console" AWS_ACCOUNT="170187898933"
AWS_CONSOLE="https://$AWS_ACCOUNT.signin.aws.amazon.com/console"
# Dove stanno le cose della persona, sul suo PC. Gli script dei progetti # Dove stanno le cose della persona, sul suo PC. Gli script dei progetti
# leggono da qui: non cambiarli senza cambiare anche loro. # leggono da qui: non cambiarli senza cambiare anche loro.
TOKEN_GITEA_FILE="$HOME/.config/oto/gitea.token" TOKEN_GITEA_FILE="$HOME/.config/oto/gitea.token"
CHIAVE_SSH="$HOME/.ssh/oto_ed25519" CHIAVE_SSH="$HOME/.ssh/oto_ed25519"
CARTELLA_PROGETTI="${CARTELLA_PROGETTI:-$HOME/Work/workspace/oto}" # I nomi con cui la cercano gli script dei progetti (STAGING_SSH_KEY e
# PRODUCTION_SSH_KEY in project.conf.sh): sono la stessa chiave, perche' sui
# server l'amministratore mette quella del profilo Gitea, cioe' questa.
CHIAVI_SSH_PROGETTI="$HOME/.ssh/oto_staging_ed25519 $HOME/.ssh/oto_production_ed25519"
# I server, con i nomi che usano gli script dei progetti. Staging sta su rete # I server, con i nomi che usano gli script dei progetti. Staging e la
# privata: senza VPN non risponde. La produzione di oggi e' quella vecchia, # produzione nuova stanno su rete privata: senza VPN non rispondono. Le
# oto-production-old: oto-production resta per la macchina nuova, e quando # produzioni sono due finche' i siti non sono migrati tutti: oto-production
# arriva la si aggiunge qui e si rilancia configura.sh. # e' la macchina nuova (dal 05/10/2026), oto-production-old quella dove
# girano ancora i siti. Sulla nuova l'utente non e' admin.
STAGING_NOME="oto-staging" STAGING_NOME="oto-staging"
STAGING_HOST="10.110.185.10" STAGING_HOST="10.110.185.10"
PRODUZIONE_NOME="oto-production-old" STAGING_UTENTE="admin"
PRODUZIONE_HOST="vps-production.oto-farm.com" PRODUZIONE_NOME="oto-production"
UTENTE_SERVER="admin" PRODUZIONE_HOST="10.110.137.20"
PRODUZIONE_UTENTE="admin.produzione"
PRODUZIONE_VECCHIA_NOME="oto-production-old"
PRODUZIONE_VECCHIA_HOST="vps-production.oto-farm.com"
PRODUZIONE_VECCHIA_UTENTE="admin"
# Un parametro che ogni ruolo di sviluppo puo' leggere: serve a verifica.sh # Un parametro che ogni ruolo di sviluppo puo' leggere: serve a verifica.sh
# per sapere se l'accesso AWS arriva davvero alla cassaforte. # per sapere se l'accesso AWS arriva davvero alla cassaforte.
@@ -41,15 +50,72 @@ titolo () { echo ; echo "${GRASSETTO}$*${FINE}" ; }
c_e () { command -v "$1" > /dev/null 2>&1 ; } c_e () { command -v "$1" > /dev/null 2>&1 ; }
# Su Mac Homebrew non si mette da solo nel PATH: senza, git e aws installati
# con brew sembrano mancare anche se ci sono.
if ! c_e brew ; then
for B in /opt/homebrew/bin/brew /usr/local/bin/brew ; do
[ -x "$B" ] && eval "$("$B" shellenv)" && break
done
fi
token_gitea () { token_gitea () {
[ -s "$TOKEN_GITEA_FILE" ] && tr -d '[:space:]' < "$TOKEN_GITEA_FILE" [ -s "$TOKEN_GITEA_FILE" ] && tr -d '[:space:]' < "$TOKEN_GITEA_FILE"
} }
# Stampa il nome utente Gitea del token, o niente se il token non vale. # Una chiamata all'API di Gitea col token salvato: il token passa a curl da
# stdin, non dalla riga di comando (che sul PC si vede con ps). Scrive il corpo
# della risposta e, sull'ultima riga, il codice HTTP (000 se Gitea non ha
# risposto). Gli argomenti in piu' vanno a curl (-X POST, -d ...).
api_gitea () {
local percorso="$1" ; shift
printf 'header = "Authorization: token %s"\n' "$(token_gitea)" \
| curl -s --max-time 15 -K - -w '\n%{http_code}' "$@" "$GITEA_URL/api/v1$percorso"
}
# Il valore di un campo testo da un JSON di Gitea, anche con gli spazi dopo i
# due punti. Basta per i campi che servono qui; un parser vero vorrebbe jq, che
# su Windows non c'e'.
campo_json () {
sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n 1
}
# Stampa il nome utente Gitea del token. Esce 1 se il token manca o Gitea lo
# rifiuta, 2 se Gitea non risponde: "non vale" e "non so" sono due cose
# diverse, e la seconda non deve far chiedere di nuovo la password.
utente_gitea () { utente_gitea () {
local token local risposta codice
token="$(token_gitea)" || return 1 [ -n "$(token_gitea)" ] || return 1
[ -n "$token" ] || return 1 risposta="$(api_gitea /user)"
curl -s --max-time 10 -H "Authorization: token $token" "$GITEA_URL/api/v1/user" \ codice="${risposta##*$'\n'}"
| sed -n 's/.*"login":"\([^"]*\)".*/\1/p' case "$codice" in
200) printf '%s' "${risposta%$'\n'*}" | campo_json login ;;
401|403) return 1 ;;
*) return 2 ;;
esac
}
# Controlla che l'identita' AWS (un ARN) sia l'utente IAM della persona
# nell'account di OTO, e non solo un utente con lo stesso nome altrove.
aws_e_di () {
[ "$1" = "arn:aws:iam::$AWS_ACCOUNT:user/$2" ]
}
# Le variabili che fanno usare alla AWS CLI un'altra chiave invece di quella
# scritta in ~/.aws/credentials: le stampa, senza i valori.
aws_variabili_in_conflitto () {
local v
for v in AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE AWS_SHARED_CREDENTIALS_FILE ; do
[ -n "${!v:-}" ] && printf '%s ' "$v"
done
}
# La credenziale che git usa davvero per Gitea, chiesta a git e non letta da
# un file: e' quella che serve per clone e pull, qualunque gestore la tenga.
# Senza nessuna domanda: nel terminale di VS Code GIT_ASKPASS aprirebbe una
# finestra di login.
password_git_gitea () {
printf 'protocol=https\nhost=%s\n\n' "$GITEA_HOST" \
| env -u GIT_ASKPASS -u SSH_ASKPASS GIT_TERMINAL_PROMPT=0 GCM_INTERACTIVE=never \
git -c credential.interactive=never credential fill 2> /dev/null \
| sed -n 's/^password=//p'
} }
+205 -62
View File
@@ -1,34 +1,64 @@
#!/bin/bash #!/bin/bash
# #
# PREPARA IL PC: accesso Gitea, accesso AWS, git, chiave SSH, nomi dei server. # PREPARA IL PC: accesso Gitea, accesso AWS, git, chiave SSH, nomi e chiavi dei server.
# #
# ./configura.sh # ./configura.sh
# #
# Si lancia nel proprio terminale: chiede la password Gitea e le chiavi AWS # Si lancia nel proprio terminale: chiede la password Gitea e la chiave AWS
# con l'input nascosto, e un assistente AI non puo' rispondere al posto tuo. # con l'input nascosto, e un assistente AI non puo' rispondere al posto tuo.
# Si puo' rilanciare: quello che e' gia' a posto non viene toccato. # Si puo' rilanciare: quello che e' gia' a posto non viene toccato.
# Non crea accessi: quelli li crea un amministratore, qui si usano. # Non crea accessi: quelli li crea un amministratore, qui si usano.
# Esce 0 se e' andato tutto, 1 se qualcosa resta da sistemare (detto in rosso).
set -u set -u
cd "$(dirname "$0")" || exit 1 cd "$(dirname "$0")" || exit 1
. ./comune.sh . ./comune.sh
# Un passo non riuscito non ferma gli altri (la chiave SSH serve anche senza
# AWS), ma si conta: alla fine "Fatto" si dice solo se non ce ne sono, e
# l'uscita e' 1, cosi' chi lo lancia da uno script non va avanti alla cieca.
ERRORI=0
errore () { male "$@" ; ERRORI=$((ERRORI + 1)) ; }
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
titolo "1. Gitea" titolo "1. Gitea"
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Alla persona si chiede la password, non un token: il token lo crea lo # Alla persona si chiede la password, non un token: il token lo crea lo
# script con l'API di Gitea, cosi' non c'e' da cercarlo fra le impostazioni. # script con l'API di Gitea, cosi' non c'e' da cercarlo fra le impostazioni.
# Gitea rifiuta la password provvisoria finche' non la si cambia nel browser. # La password e' nella scheda LastPass "Gitea > nome.cognome", condivisa da
UTENTE="$(utente_gitea)" # chi amministra (nella mail non c'e', apposta): dal 07/10/2026 Gitea non
# obbliga piu' a cambiarla. Chi e' stato creato prima invece deve ancora
# cambiarla nel browser, e Gitea gli risponde 403: lo si dice sotto.
UTENTE="$(utente_gitea)" ; ESITO_GITEA=$?
# Gitea che non risponde non vuol dire token sbagliato: chiedere la password e
# creare un altro token non servirebbe a niente. Ci si ferma qui, perche' tutto
# il resto (chi e' la persona, dove va la chiave SSH) lo dice Gitea.
if [ "$ESITO_GITEA" = "2" ] ; then
male "Gitea ($GITEA_URL) non risponde: controlla la connessione a internet e rilancia."
exit 1
fi
# I token creati prima del 07/10/2026 hanno read:organization e non
# write:organization, che serve a creare i progetti nell'organizzazione oto.
# Lo si chiede a Gitea con una creazione volutamente incompleta (senza nome):
# a un token senza lo scope risponde 403 citandolo, a uno giusto 422, e in
# nessuno dei due casi crea niente. Il token vecchio si mette da parte e se ne
# crea uno nuovo qui sotto; quello vecchio si cancella dal proprio profilo.
if [ -n "$UTENTE" ] && api_gitea /orgs/oto/repos -X POST -H 'Content-Type: application/json' -d '{}' \
| grep -q 'write:organization' ; then
mv "$TOKEN_GITEA_FILE" "$TOKEN_GITEA_FILE.vecchio"
attento "il token Gitea salvato non puo' creare progetti nell'organizzazione: ne creo uno nuovo"
echo " (quello vecchio, in $TOKEN_GITEA_FILE.vecchio, cancellalo dal tuo profilo Gitea:"
echo " Impostazioni -> Applicazioni)"
UTENTE=""
fi
if [ -n "$UTENTE" ] ; then if [ -n "$UTENTE" ] ; then
ok "token Gitea gia' salvato (utente $UTENTE)" ok "token Gitea gia' salvato (utente $UTENTE)"
else else
echo " Utente e password provvisoria di Gitea sono nel messaggio di benvenuto" echo " L'utente Gitea e' nella mail \"I tuoi accessi OTO\" che ti ha mandato chi"
echo " di chi amministra. Se non l'hai ancora fatto, entra su $GITEA_URL" echo " amministra. La password no: e' su LastPass, nella scheda \"Gitea > nome.cognome\""
echo " (Sign in, in alto a destra) e cambia la password provvisoria: qui serve" echo " col tuo utente (per esempio \"Gitea > sara.locatelli\"), campo Password."
echo " quella nuova, e Gitea rifiuta la provvisoria." read -r -p " Il tuo utente Gitea (dalla mail, riga utente Gitea): " UTENTE_DATO
read -r -p " Il tuo utente Gitea (nome.cognome, come nel messaggio di benvenuto): " UTENTE_DATO read -r -s -p " La tua password Gitea, dalla scheda LastPass \"Gitea > $UTENTE_DATO\" (non si vede, ed e' normale): " PASSWORD ; echo
read -r -s -p " La tua password Gitea nuova (non si vede, ed e' normale): " PASSWORD ; echo
# utente:password passano a curl da stdin, non dalla riga di comando # utente:password passano a curl da stdin, non dalla riga di comando
# (che chiunque sul PC vede con ps). Virgolette e \ vanno protette. # (che chiunque sul PC vede con ps). Virgolette e \ vanno protette.
PASSWORD_CURL="$(printf '%s:%s' "$UTENTE_DATO" "$PASSWORD" | sed 's/[\\"]/\\&/g')" PASSWORD_CURL="$(printf '%s:%s' "$UTENTE_DATO" "$PASSWORD" | sed 's/[\\"]/\\&/g')"
@@ -36,58 +66,97 @@ else
RISPOSTA="$(printf 'user = "%s"\n' "$PASSWORD_CURL" \ RISPOSTA="$(printf 'user = "%s"\n' "$PASSWORD_CURL" \
| curl -s --max-time 15 -K - -w '\n%{http_code}' -X POST \ | curl -s --max-time 15 -K - -w '\n%{http_code}' -X POST \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "{\"name\":\"$NOME_TOKEN\",\"scopes\":[\"write:repository\",\"write:user\",\"read:organization\"]}" \ -d "{\"name\":\"$NOME_TOKEN\",\"scopes\":[\"write:repository\",\"write:user\",\"write:organization\"]}" \
"$GITEA_URL/api/v1/users/$UTENTE_DATO/tokens")" "$GITEA_URL/api/v1/users/$UTENTE_DATO/tokens")"
unset PASSWORD PASSWORD_CURL unset PASSWORD PASSWORD_CURL
CODICE="${RISPOSTA##*$'\n'}" CODICE="${RISPOSTA##*$'\n'}"
TOKEN="$(printf '%s' "${RISPOSTA%$'\n'*}" | sed -n 's/.*"sha1":"\([^"]*\)".*/\1/p')" TOKEN="$(printf '%s' "${RISPOSTA%$'\n'*}" | campo_json sha1)"
if [ "$CODICE" = "201" ] && [ -n "$TOKEN" ] ; then if [ "$CODICE" = "201" ] && [ -n "$TOKEN" ] ; then
mkdir -p "$(dirname "$TOKEN_GITEA_FILE")" mkdir -p "$(dirname "$TOKEN_GITEA_FILE")"
chmod 700 "$(dirname "$TOKEN_GITEA_FILE")" chmod 700 "$(dirname "$TOKEN_GITEA_FILE")"
( umask 077 ; printf '%s\n' "$TOKEN" > "$TOKEN_GITEA_FILE" ) ( umask 077 ; printf '%s\n' "$TOKEN" > "$TOKEN_GITEA_FILE" )
chmod 600 "$TOKEN_GITEA_FILE"
unset TOKEN unset TOKEN
UTENTE="$(utente_gitea)" UTENTE="$(utente_gitea)"
if [ -n "$UTENTE" ] ; then
ok "accesso Gitea salvato in $TOKEN_GITEA_FILE (utente $UTENTE)" ok "accesso Gitea salvato in $TOKEN_GITEA_FILE (utente $UTENTE)"
elif [ "$CODICE" = "403" ] ; then
male "Gitea chiede prima di cambiare la password provvisoria: entra su $GITEA_URL, cambiala e rilancia."
elif [ "$CODICE" = "401" ] ; then
male "utente o password sbagliati: rilancia e riprova."
else else
male "Gitea non ha creato l'accesso (HTTP ${CODICE:-nessuna risposta}): rilancia, o chiedi all'amministratore." errore "Gitea ha creato l'accesso ma non lo riconosce: rilancia, e se si ripete avvisa l'amministratore."
fi
elif [ "$CODICE" = "403" ] ; then
errore "Gitea chiede prima di cambiare la password: entra su $GITEA_URL (Sign in), scegline una nuova, salvala su LastPass e rilancia."
elif [ "$CODICE" = "401" ] ; then
errore "utente o password sbagliati: rilancia e riprova."
else
errore "Gitea non ha creato l'accesso (HTTP ${CODICE:-nessuna risposta}): rilancia, o chiedi all'amministratore."
fi fi
fi fi
# git: chi sei, e come si ricorda le credenziali. Il token vale anche come # git: chi sei, e come entra su Gitea. Il token vale anche come password per
# password per git: lo si scrive una volta in ~/.git-credentials. # git, e lo tiene il gestore "store" (il file ~/.git-credentials) per il solo
# indirizzo di Gitea: un gestore gia' configurato per tutto il resto (quello di
# Windows o del Mac, per dire) non si tocca, ma per Gitea non viene interrogato,
# cosi' non risponde con un accesso vecchio o con una finestra di login.
if [ -n "$UTENTE" ] ; then if [ -n "$UTENTE" ] ; then
[ -n "$(git config --global user.name)" ] || git config --global user.name "$UTENTE" [ -n "$(git config --global user.name)" ] || git config --global user.name "$UTENTE"
if [ -z "$(git config --global user.email)" ] ; then if [ -z "$(git config --global user.email)" ] ; then
read -r -p " La tua email di lavoro, quella @oto.agency (firma le tue modifiche al codice): " EMAIL read -r -p " La tua email di lavoro, quella @oto.agency (firma le tue modifiche al codice): " EMAIL
[ -n "$EMAIL" ] && git config --global user.email "$EMAIL" [ -n "$EMAIL" ] && git config --global user.email "$EMAIL"
fi fi
[ -n "$(git config --global credential.helper)" ] || git config --global credential.helper store # La riga vuota azzera, per questo indirizzo, i gestori configurati prima.
CREDENZIALI="$HOME/.git-credentials" git config --global --unset-all "credential.$GITEA_URL.helper" 2> /dev/null
if ! grep -q "@$GITEA_HOST" "$CREDENZIALI" 2> /dev/null ; then git config --global --add "credential.$GITEA_URL.helper" ""
( umask 077 ; printf 'https://%s:%s@%s\n' "$UTENTE" "$(token_gitea)" "$GITEA_HOST" >> "$CREDENZIALI" ) git config --global --add "credential.$GITEA_URL.helper" store
# Se git ha ancora il token di prima (rinnovato qui sopra, o revocato), la
# credenziale si sostituisce: prima si aggiungeva solo se mancava, e restava
# quella vecchia, con l'API che funzionava e git clone che no. Passa da git,
# su stdin, e tocca la sola voce di Gitea.
if [ "$(password_git_gitea)" != "$(token_gitea)" ] ; then
printf 'protocol=https\nhost=%s\n\n' "$GITEA_HOST" | git credential reject
printf 'protocol=https\nhost=%s\nusername=%s\npassword=%s\n\n' "$GITEA_HOST" "$UTENTE" "$(token_gitea)" \
| git credential approve
fi fi
[ -f "$HOME/.git-credentials" ] && chmod 600 "$HOME/.git-credentials"
if [ "$(password_git_gitea)" = "$(token_gitea)" ] ; then
ok "git configurato ($(git config --global user.name) <$(git config --global user.email)>)" ok "git configurato ($(git config --global user.name) <$(git config --global user.email)>)"
else
errore "git non riesce a ricordare l'accesso a Gitea: avvisa l'amministratore, con il messaggio qui sopra."
fi
fi fi
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
titolo "2. AWS" titolo "2. AWS"
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# La chiave di accesso la crea la persona dalla console (Security # La chiave di accesso la crea chi amministra insieme all'utente, e la
# credentials → Create access key): qui la si incolla una volta e finisce in # persona la trova su LastPass, nel campo di testo della scheda
# ~/.aws/credentials, dove la leggono la AWS CLI e gli script dei progetti. # "AWS > Nome Cognome": qui la si incolla
# una volta e finisce in ~/.aws/credentials, dove la leggono la AWS CLI e gli
# script dei progetti. Se non ce l'ha (e' arrivata prima, o l'ha persa), se
# ne crea una dalla console: la strada e' scritta qui sotto.
# #
# Viene dopo Gitea apposta: e' Gitea, con la password, a dire chi e' la # Viene dopo Gitea apposta: e' Gitea, con la password, a dire chi e' la
# persona. Una chiave gia' presente sul PC non basta a dirlo: puo' essere # persona. Una chiave gia' presente sul PC non basta a dirlo: puo' essere
# rimasta da chi lo usava prima, o copiata da un collega, e allora tutto # rimasta da chi lo usava prima, o copiata da un collega, e allora tutto
# quello che la persona fa su AWS risulterebbe fatto da un altro. # quello che la persona fa su AWS risulterebbe fatto da un altro. Per questo
# senza Gitea il passo si salta, invece di dare per buona una chiave qualsiasi.
#
# La chiave si scrive nel profilo "default" e si controlla con quello: se
# AWS_PROFILE o le variabili AWS_ACCESS_KEY_ID... sono impostate, la AWS CLI
# userebbe altro, e lo si dice.
AWS_OPZ=(--profile default --cli-connect-timeout 10 --cli-read-timeout 15)
identita_aws () {
AWS_MAX_ATTEMPTS=1 aws sts get-caller-identity "${AWS_OPZ[@]}" --query Arn --output text 2> /dev/null
}
chiedi_chiave_aws () { chiedi_chiave_aws () {
echo " Serve la tua chiave di accesso AWS, due pezzi. La crei tu, nella console AWS:" echo " Serve la tua chiave di accesso AWS, due pezzi: Access key ID e Secret access key."
echo " 1. entra su $AWS_CONSOLE (IAM user, utente e password" # Il nome della scheda e' quello per esteso: sara.locatelli -> Sara Locatelli.
echo " del messaggio di benvenuto);" SCHEDA_AWS="AWS > $(printf '%s' "$UTENTE" | awk -F. '{for (i = 1; i <= NF; i++) printf "%s%s", (i > 1 ? " " : ""), toupper(substr($i, 1, 1)) substr($i, 2)}')"
echo " Non sono nella mail: li trovi su LastPass, nella scheda \"$SCHEDA_AWS\" che ti"
echo " ha condiviso chi amministra, nel campo di testo (righe Access key ID e Secret"
echo " access key). Se li' non c'e', la crei tu nella console AWS:"
echo " 1. entra su $AWS_CONSOLE (IAM user, utente, password e"
echo " codice a due fattori dalla stessa scheda LastPass);"
echo " 2. il tuo nome in alto a destra → Security credentials;" echo " 2. il tuo nome in alto a destra → Security credentials;"
echo " 3. riquadro Access keys → Create access key → Command Line Interface (CLI)," echo " 3. riquadro Access keys → Create access key → Command Line Interface (CLI),"
echo " spunta la conferma → Next → Create access key." echo " spunta la conferma → Next → Create access key."
@@ -100,36 +169,64 @@ chiedi_chiave_aws () {
CHIAVE_ID="$(printf '%s' "$CHIAVE_ID" | tr -d '[:space:]')" CHIAVE_ID="$(printf '%s' "$CHIAVE_ID" | tr -d '[:space:]')"
CHIAVE_SEGRETA="$(printf '%s' "$CHIAVE_SEGRETA" | tr -d '[:space:]')" CHIAVE_SEGRETA="$(printf '%s' "$CHIAVE_SEGRETA" | tr -d '[:space:]')"
if [ -z "$CHIAVE_ID" ] || [ -z "$CHIAVE_SEGRETA" ] ; then if [ -z "$CHIAVE_ID" ] || [ -z "$CHIAVE_SEGRETA" ] ; then
male "chiave non inserita: rilancia quando ce l'hai." ; unset CHIAVE_SEGRETA ; return 1 errore "chiave non inserita: rilancia quando ce l'hai." ; unset CHIAVE_SEGRETA ; return 1
fi fi
aws configure set aws_access_key_id "$CHIAVE_ID" # Si prova PRIMA di salvarla, passandola per variabili d'ambiente (che non
aws configure set aws_secret_access_key "$CHIAVE_SEGRETA" # si vedono con ps): una chiave sbagliata, o di un altro, non deve prendere
aws configure set region "$AWS_REGIONE" # il posto di quella che c'era.
local nuova
nuova="$(env -u AWS_PROFILE -u AWS_SESSION_TOKEN -u AWS_SHARED_CREDENTIALS_FILE \
AWS_ACCESS_KEY_ID="$CHIAVE_ID" AWS_SECRET_ACCESS_KEY="$CHIAVE_SEGRETA" AWS_MAX_ATTEMPTS=1 \
aws sts get-caller-identity --cli-connect-timeout 10 --cli-read-timeout 15 --query Arn --output text 2> /dev/null)"
if [ -z "$nuova" ] ; then
unset CHIAVE_SEGRETA unset CHIAVE_SEGRETA
if ! IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then errore "AWS non accetta questa chiave: controlla di aver copiato i due pezzi interi, senza scambiarli, e rilancia. Non l'ho salvata."
male "AWS non accetta questa chiave: controlla di aver copiato i due pezzi interi, o creane un'altra." return 1
elif [ -n "$UTENTE" ] && [ "${IDENTITA##*/}" != "$UTENTE" ] ; then
male "questa chiave e' di ${IDENTITA##*/}, non tua ($UTENTE): crea la tua dalla console AWS, entrando col tuo utente, e rilancia."
else
ok "accesso AWS: ${IDENTITA##*/}"
fi fi
if ! aws_e_di "$nuova" "$UTENTE" ; then
unset CHIAVE_SEGRETA
errore "questa chiave e' di ${nuova#arn:aws:iam::}, non tua ($UTENTE nell'account OTO $AWS_ACCOUNT): usa quella della tua scheda LastPass \"$SCHEDA_AWS\", e rilancia. Non l'ho salvata."
return 1
fi
# aws configure set la vuole come argomento: per l'attimo in cui gira si
# vede con ps. Non c'e' un'alternativa da stdin, e su un PC personale e'
# un rischio accettato.
aws configure set aws_access_key_id "$CHIAVE_ID" --profile default \
&& aws configure set aws_secret_access_key "$CHIAVE_SEGRETA" --profile default \
&& aws configure set region "$AWS_REGIONE" --profile default
local esito=$?
unset CHIAVE_SEGRETA
[ -f "$HOME/.aws/credentials" ] && chmod 600 "$HOME/.aws/credentials"
if [ "$esito" != "0" ] ; then
errore "non riesco a salvare la chiave in ~/.aws/credentials: avvisa l'amministratore, con il messaggio qui sopra."
return 1
fi
ok "accesso AWS: $UTENTE"
} }
if ! c_e aws ; then if ! c_e aws ; then
male "AWS CLI non installata: installala e rilancia questo script." errore "AWS CLI non installata: installala e rilancia questo script."
elif IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then elif [ -z "$UTENTE" ] ; then
if [ -z "$UTENTE" ] || [ "${IDENTITA##*/}" = "$UTENTE" ] ; then errore "AWS saltato: prima deve funzionare Gitea (passo 1), che dice chi sei. Sistemato quello, rilancia."
ok "accesso AWS: ${IDENTITA##*/}"
else else
attento "su questo PC c'e' gia' una chiave AWS, ma e' di ${IDENTITA##*/}, non tua ($UTENTE)." CONFLITTI="$(aws_variabili_in_conflitto)"
echo " Usandola, tutto quello che fai su AWS risulterebbe fatto da ${IDENTITA##*/}." if [ -n "$CONFLITTI" ] ; then
attento "nel terminale sono impostate $CONFLITTI: la AWS CLI usera' quelle e non la chiave salvata qui. Se non sai perche' ci sono, dillo all'amministratore."
fi
if IDENTITA="$(identita_aws)" && [ -n "$IDENTITA" ] ; then
if aws_e_di "$IDENTITA" "$UTENTE" ; then
ok "accesso AWS: $UTENTE"
else
attento "su questo PC c'e' gia' una chiave AWS, ma e' di ${IDENTITA#arn:aws:iam::}, non tua ($UTENTE)."
echo " Usandola, tutto quello che fai su AWS risulterebbe fatto da un altro."
echo " La sostituisco con la tua. Avvisa l'amministratore: quella chiave e' uscita" echo " La sostituisco con la tua. Avvisa l'amministratore: quella chiave e' uscita"
echo " dal PC di ${IDENTITA##*/} e va disattivata." echo " dal PC del suo proprietario e va disattivata."
chiedi_chiave_aws chiedi_chiave_aws
fi fi
else else
chiedi_chiave_aws chiedi_chiave_aws
fi fi
fi
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
titolo "3. Chiave SSH" titolo "3. Chiave SSH"
@@ -139,26 +236,38 @@ if [ -f "$CHIAVE_SSH" ] ; then
else else
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh" mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
COMMENTO="${UTENTE:-$(whoami)}@oto" COMMENTO="${UTENTE:-$(whoami)}@oto"
ssh-keygen -q -t ed25519 -f "$CHIAVE_SSH" -C "$COMMENTO" -N "" \ if ssh-keygen -q -t ed25519 -f "$CHIAVE_SSH" -C "$COMMENTO" -N "" ; then
&& ok "chiave creata: $CHIAVE_SSH" ok "chiave creata: $CHIAVE_SSH"
else
errore "non riesco a creare la chiave SSH: avvisa l'amministratore, con il messaggio qui sopra."
fi
fi
# Gli script dei progetti la cercano con altri nomi (staging e produzione):
# sono collegamenti a questa, non chiavi nuove. Un file che c'e' gia' con
# quel nome e' una chiave tua di prima, e non si tocca.
if [ -f "$CHIAVE_SSH" ] ; then
for ALTRA in $CHIAVI_SSH_PROGETTI ; do
[ -e "$ALTRA" ] && continue
ln -s "$(basename "$CHIAVE_SSH")" "$ALTRA" 2> /dev/null || cp -p "$CHIAVE_SSH" "$ALTRA" \
|| errore "non riesco a creare $ALTRA: i deploy dei progetti non troverebbero la chiave."
done
fi fi
# La parte pubblica va sul proprio profilo Gitea: e' da li' che # La parte pubblica va sul proprio profilo Gitea: e' da li' che
# l'amministratore la prende per metterla sui server, senza che la persona # l'amministratore la prende per metterla sui server, senza che la persona
# debba mandarla a nessuno. # debba mandarla a nessuno.
if [ -f "$CHIAVE_SSH.pub" ] && [ -n "$UTENTE" ] ; then if [ -f "$CHIAVE_SSH.pub" ] && [ -n "$UTENTE" ] ; then
PUBBLICA="$(awk '{print $1" "$2}' "$CHIAVE_SSH.pub")" PUBBLICA="$(awk '{print $1" "$2}' "$CHIAVE_SSH.pub")"
if curl -s --max-time 10 -H "Authorization: token $(token_gitea)" "$GITEA_URL/api/v1/user/keys" \ CHIAVI="$(api_gitea /user/keys)"
| grep -qF "${PUBBLICA#* }" ; then if [ "${CHIAVI##*$'\n'}" = "200" ] && printf '%s' "$CHIAVI" | grep -qF "${PUBBLICA#* }" ; then
ok "chiave pubblica gia' sul tuo profilo Gitea" ok "chiave pubblica gia' sul tuo profilo Gitea"
else else
CODICE="$(curl -s -o /dev/null --max-time 10 -w '%{http_code}' -X POST \ CODICE="$(api_gitea /user/keys -o /dev/null -X POST -H 'Content-Type: application/json' \
-H "Authorization: token $(token_gitea)" -H 'Content-Type: application/json' \ -d "{\"title\":\"oto $(hostname | tr -dc 'A-Za-z0-9-')\",\"key\":\"$PUBBLICA\"}")"
-d "{\"title\":\"oto $(hostname | tr -dc 'A-Za-z0-9-')\",\"key\":\"$PUBBLICA\"}" \ CODICE="${CODICE##*$'\n'}"
"$GITEA_URL/api/v1/user/keys")"
if [ "$CODICE" = "201" ] ; then if [ "$CODICE" = "201" ] ; then
ok "chiave pubblica caricata sul tuo profilo Gitea: l'amministratore la prende da li'" ok "chiave pubblica caricata sul tuo profilo Gitea: l'amministratore la prende da li'"
else else
attento "non riesco a caricare la chiave su Gitea (HTTP $CODICE). Manda all'amministratore questa riga, e' la parte pubblica:" errore "non riesco a caricare la chiave su Gitea (HTTP $CODICE). Manda all'amministratore questa riga, e' la parte pubblica:"
echo " $(cat "$CHIAVE_SSH.pub")" echo " $(cat "$CHIAVE_SSH.pub")"
fi fi
fi fi
@@ -172,6 +281,7 @@ titolo "4. Nomi dei server in ~/.ssh/config"
# un server basta rilanciare. Un nome gia' definito fuori dal blocco non si # un server basta rilanciare. Un nome gia' definito fuori dal blocco non si
# tocca (e' una configurazione tua). # tocca (e' una configurazione tua).
CONFIG="$HOME/.ssh/config" CONFIG="$HOME/.ssh/config"
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
touch "$CONFIG" && chmod 600 "$CONFIG" touch "$CONFIG" && chmod 600 "$CONFIG"
INIZIO="# >>> OTO (scritto da _OTO_IT_onboard/configura.sh) >>>" INIZIO="# >>> OTO (scritto da _OTO_IT_onboard/configura.sh) >>>"
FINE_BLOCCO="# <<< OTO <<<" FINE_BLOCCO="# <<< OTO <<<"
@@ -182,7 +292,9 @@ FUORI="$(awk -v i="$INIZIO" -v f="$FINE_BLOCCO" '$0 == i {dentro=1; next} $0 ==
# /c/Users/..., che l'OpenSSH di Windows (quello di VS Code) non capisce. # /c/Users/..., che l'OpenSSH di Windows (quello di VS Code) non capisce.
CHIAVE_CONFIG="~${CHIAVE_SSH#"$HOME"}" CHIAVE_CONFIG="~${CHIAVE_SSH#"$HOME"}"
BLOCCO="$INIZIO" BLOCCO="$INIZIO"
for VOCE in "$STAGING_NOME $STAGING_HOST" "$PRODUZIONE_NOME $PRODUZIONE_HOST" ; do for VOCE in "$STAGING_NOME $STAGING_HOST $STAGING_UTENTE" \
"$PRODUZIONE_NOME $PRODUZIONE_HOST $PRODUZIONE_UTENTE" \
"$PRODUZIONE_VECCHIA_NOME $PRODUZIONE_VECCHIA_HOST $PRODUZIONE_VECCHIA_UTENTE" ; do
set -- $VOCE set -- $VOCE
if printf '%s\n' "$FUORI" | grep -qE "^Host[[:space:]]+$1([[:space:]]|\$)" ; then if printf '%s\n' "$FUORI" | grep -qE "^Host[[:space:]]+$1([[:space:]]|\$)" ; then
attento "$1 e' gia' definito in $CONFIG: lo lascio com'e'" attento "$1 e' gia' definito in $CONFIG: lo lascio com'e'"
@@ -191,18 +303,49 @@ for VOCE in "$STAGING_NOME $STAGING_HOST" "$PRODUZIONE_NOME $PRODUZIONE_HOST" ;
BLOCCO="$BLOCCO BLOCCO="$BLOCCO
Host $1 Host $1
HostName $2 HostName $2
User $UTENTE_SERVER User $3
IdentitiesOnly yes IdentitiesOnly yes
IdentityFile $CHIAVE_CONFIG IdentityFile $CHIAVE_CONFIG
" "
done done
BLOCCO="$BLOCCO$FINE_BLOCCO" BLOCCO="$BLOCCO$FINE_BLOCCO"
{ printf '%s\n' "$FUORI" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' ; echo ; printf '%s\n' "$BLOCCO" ; } > "$CONFIG.nuovo" \ if { printf '%s\n' "$FUORI" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' ; echo ; printf '%s\n' "$BLOCCO" ; } > "$CONFIG.nuovo" \
&& mv "$CONFIG.nuovo" "$CONFIG" && chmod 600 "$CONFIG" && mv "$CONFIG.nuovo" "$CONFIG" && chmod 600 "$CONFIG" ; then
ok "ssh $STAGING_NOME e ssh $PRODUZIONE_NOME: configurati" ok "ssh $STAGING_NOME, ssh $PRODUZIONE_NOME e ssh $PRODUZIONE_VECCHIA_NOME: configurati"
else
rm -f "$CONFIG.nuovo"
errore "non riesco a scrivere $CONFIG: i nomi dei server non sono configurati."
fi
# --------------------------------------------------------------------------
titolo "5. Chiavi dei server in ~/.ssh/known_hosts"
# --------------------------------------------------------------------------
# Quelle di server.known_hosts, lette sulle macchine: cosi' il primo
# collegamento non chiede "Are you sure you want to continue connecting?",
# e la risposta non dipende da chi e' in mezzo alla rete quel giorno. Quelle
# che c'erano per gli stessi nomi si tolgono prima (ssh-keygen ne lascia una
# copia in known_hosts.old): una vecchia rimasta li' farebbe dire a ssh che
# il server e' cambiato. Quando un server cambia chiave davvero, la nuova si
# legge sulla macchina e si scrive in server.known_hosts, in questo
# repository: e' l'unico posto da cui la prendono i PC.
NOTI="$HOME/.ssh/known_hosts"
touch "$NOTI" && chmod 600 "$NOTI"
for H in $(grep -v '^#' server.known_hosts | awk 'NF {print $1}' | sort -u) ; do
ssh-keygen -R "$H" -f "$NOTI" > /dev/null 2>&1
done
if grep -v '^#' server.known_hosts | awk 'NF' >> "$NOTI" ; then
ok "chiavi di $STAGING_NOME, $PRODUZIONE_NOME e $PRODUZIONE_VECCHIA_NOME registrate"
else
errore "non riesco a scrivere $NOTI: ssh chiedera' conferma al primo collegamento."
fi
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
titolo "Fatto" titolo "Fatto"
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
echo " Ora: importa il file della VPN, poi lancia ./verifica.sh" if [ "$ERRORI" != "0" ] ; then
if [ "$ERRORI" = "1" ] ; then male "una cosa non e' andata (sopra, in rosso): sistemala e rilancia ./configura.sh."
else male "$ERRORI cose non sono andate (sopra, in rosso): sistemale e rilancia ./configura.sh." ; fi
exit 1
fi
echo " Ora: se su LastPass hai la scheda \"OTO > VPN HK $UTENTE\", accendi la VPN (file e credenziali sono li'); poi torna da Claude."
+89 -24
View File
@@ -2,31 +2,75 @@
# #
# SCARICA I PROGETTI A CUI HAI ACCESSO SU GITEA. # SCARICA I PROGETTI A CUI HAI ACCESSO SU GITEA.
# #
# ./progetti.sh # elenca e chiede quali scaricare # ./progetti.sh # chiede dove e quali scaricare
# ./progetti.sh nome1 nome2 # scarica questi # ./progetti.sh --in CARTELLA nome1 nome2 # scarica questi in CARTELLA
# #
# Li mette in $CARTELLA_PROGETTI (di solito ~/Work/workspace/oto). Un progetto # La cartella la sceglie la persona, ogni volta: non c'e' un posto di default
# gia' scaricato non si tocca. Vedi solo i repository che l'amministratore ti # (fino al 13/10/2026 era ~/Work/workspace/oto, cioe' la cartella di chi ha
# scritto lo script). Si passa con --in o con CARTELLA_PROGETTI; senza, lo
# script la chiede, e se non puo' chiederla si ferma. Un progetto gia'
# scaricato non si tocca. Vedi solo i repository che l'amministratore ti
# ha dato: se ne manca uno, e' da chiedere a lui. # ha dato: se ne manca uno, e' da chiedere a lui.
# Esce 1 se un progetto chiesto non e' stato scaricato.
set -u set -u
cd "$(dirname "$0")" || exit 1 cd "$(dirname "$0")" || exit 1
. ./comune.sh . ./comune.sh
TOKEN="$(token_gitea)" if [ "${1:-}" = "--in" ] ; then
if [ -z "$TOKEN" ] || [ -z "$(utente_gitea)" ] ; then if [ -z "${2:-}" ] ; then
male "token Gitea mancante o non valido: lancia prima ./configura.sh" male "--in vuole una cartella: ./progetti.sh --in CARTELLA nome1 nome2"
exit 1
fi
CARTELLA_PROGETTI="$2"
shift 2
fi
CARTELLA_PROGETTI="${CARTELLA_PROGETTI:-}"
if [ -z "$CARTELLA_PROGETTI" ] ; then
if [ ! -t 0 ] ; then
male "manca la cartella in cui scaricare: ./progetti.sh --in CARTELLA nome1 nome2"
exit 1
fi
read -r -p "In quale cartella scarico i progetti? " CARTELLA_PROGETTI
if [ -z "$CARTELLA_PROGETTI" ] ; then
male "nessuna cartella scelta: non scarico niente"
exit 1
fi
fi
# La tilde fra virgolette la shell non la espande, e su Windows la persona
# puo' scrivere C:\Users\...: in Git Bash cygpath la porta nella forma /c/...
case "$CARTELLA_PROGETTI" in
"~") CARTELLA_PROGETTI="$HOME" ;;
"~/"*) CARTELLA_PROGETTI="$HOME/${CARTELLA_PROGETTI#\~/}" ;;
esac
c_e cygpath && CARTELLA_PROGETTI="$(cygpath -u "$CARTELLA_PROGETTI")"
if [ -z "$(token_gitea)" ] ; then
male "token Gitea mancante: lancia prima ./configura.sh"
exit 1 exit 1
fi fi
# Tutti i repository visibili, pagina per pagina. # Tutti i repository visibili, pagina per pagina. Ci si ferma solo su una
# pagina vuota vera ("[]"): un errore di Gitea a meta' non deve diventare
# "non vedi nessun progetto", ne' un elenco tagliato senza dirlo.
ELENCO="" ELENCO=""
PAGINA=1 PAGINA=1
while : ; do while : ; do
BLOCCO="$(curl -s --max-time 15 -H "Authorization: token $TOKEN" \ RISPOSTA="$(api_gitea "/user/repos?limit=50&page=$PAGINA")"
"$GITEA_URL/api/v1/user/repos?limit=50&page=$PAGINA" \ CODICE="${RISPOSTA##*$'\n'}"
| grep -o '"full_name":"[^"]*"' | sed 's/"full_name":"\(.*\)"/\1/')" CORPO="${RISPOSTA%$'\n'*}"
[ -z "$BLOCCO" ] && break case "$CODICE" in
200) ;;
401|403) male "Gitea non accetta il tuo token: rilancia ./configura.sh" ; exit 1 ;;
000) male "Gitea ($GITEA_URL) non risponde: controlla la connessione e rilancia" ; exit 1 ;;
*) male "Gitea ha risposto HTTP $CODICE alla pagina $PAGINA dell'elenco: rilancia, e se si ripete avvisa l'amministratore" ; exit 1 ;;
esac
[ "$(printf '%s' "$CORPO" | tr -d '[:space:]')" = "[]" ] && break
BLOCCO="$(printf '%s' "$CORPO" | grep -o '"full_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/')"
if [ -z "$BLOCCO" ] ; then
male "non capisco la risposta di Gitea alla pagina $PAGINA dell'elenco: avvisa l'amministratore"
exit 1
fi
ELENCO="$ELENCO ELENCO="$ELENCO
$BLOCCO" $BLOCCO"
PAGINA=$((PAGINA + 1)) PAGINA=$((PAGINA + 1))
@@ -38,46 +82,67 @@ if [ -z "$ELENCO" ] ; then
exit 0 exit 0
fi fi
# I nomi si scelgono corti (apulia_ecommerce) o completi (oto/apulia_ecommerce).
# Si tiene il nome completo: lo stesso nome corto in due organizzazioni e'
# ambiguo, e lo si dice invece di prendere il primo.
if [ "$#" -gt 0 ] ; then if [ "$#" -gt 0 ] ; then
SCELTI="$*" SCELTI="$*"
else else
titolo "Progetti che puoi scaricare" titolo "Progetti che puoi scaricare"
printf '%s\n' "$ELENCO" | sed 's#.*/##' | nl -w3 -s'. ' printf '%s\n' "$ELENCO" | nl -w3 -s'. '
echo echo
read -r -p "Numeri o nomi, separati da spazio (invio = nessuno, 'tutti' = tutti): " RISPOSTA read -r -p "Numeri o nomi, separati da spazio (invio = nessuno, 'tutti' = tutti): " RISPOSTA
[ -z "$RISPOSTA" ] && exit 0 [ -z "$RISPOSTA" ] && exit 0
if [ "$RISPOSTA" = "tutti" ] ; then if [ "$RISPOSTA" = "tutti" ] ; then
SCELTI="$(printf '%s\n' "$ELENCO" | sed 's#.*/##')" SCELTI="$ELENCO"
else else
SCELTI="" SCELTI=""
for R in $RISPOSTA ; do for R in $RISPOSTA ; do
case "$R" in case "$R" in
*[!0-9]*) SCELTI="$SCELTI $R" ;; *[!0-9]*) SCELTI="$SCELTI $R" ;;
*) SCELTI="$SCELTI $(printf '%s\n' "$ELENCO" | sed -n "${R}p" | sed 's#.*/##')" ;; *) SCELTI="$SCELTI $(printf '%s\n' "$ELENCO" | sed -n "${R}p")" ;;
esac esac
done done
fi fi
fi fi
mkdir -p "$CARTELLA_PROGETTI" ERRORI=0
if ! mkdir -p "$CARTELLA_PROGETTI" ; then
male "non riesco a creare $CARTELLA_PROGETTI"
exit 1
fi
titolo "Scarico in $CARTELLA_PROGETTI" titolo "Scarico in $CARTELLA_PROGETTI"
for NOME in $SCELTI ; do for NOME in $SCELTI ; do
COMPLETO="$(printf '%s\n' "$ELENCO" | grep -E "/$NOME\$" | head -n 1)" # Confronto esatto, non una regex: il nome lo scrive la persona.
if [ -z "$COMPLETO" ] ; then COMPLETI="$(printf '%s\n' "$ELENCO" | awk -v n="$NOME" '$0 == n || substr($0, index($0, "/") + 1) == n')"
male "$NOME: non lo vedi su Gitea" if [ -z "$COMPLETI" ] ; then
male "$NOME: non lo vedi su Gitea (se ti serve, chiedilo all'amministratore)"
ERRORI=$((ERRORI + 1))
continue continue
fi fi
if [ -d "$CARTELLA_PROGETTI/$NOME/.git" ] ; then if [ "$(printf '%s\n' "$COMPLETI" | wc -l)" -gt 1 ] ; then
ok "$NOME: gia' scaricato" male "$NOME: c'e' in piu' di un'organizzazione ($(printf '%s ' $COMPLETI)): scrivi il nome completo"
ERRORI=$((ERRORI + 1))
continue continue
fi fi
if git clone -q "$GITEA_URL/$COMPLETO.git" "$CARTELLA_PROGETTI/$NOME" ; then CORTO="${COMPLETI#*/}"
ok "$NOME" if [ -d "$CARTELLA_PROGETTI/$CORTO/.git" ] ; then
ok "$CORTO: gia' scaricato"
continue
fi
if git clone -q "$GITEA_URL/$COMPLETI.git" "$CARTELLA_PROGETTI/$CORTO" ; then
ok "$CORTO"
else else
male "$NOME: git clone non riuscito" male "$CORTO: git clone non riuscito (il messaggio di git e' qui sopra)"
ERRORI=$((ERRORI + 1))
fi fi
done done
echo echo
if [ "$ERRORI" != "0" ] ; then
if [ "$ERRORI" = "1" ] ; then male "un progetto non scaricato (sopra, in rosso)"
else male "$ERRORI progetti non scaricati (sopra, in rosso)" ; fi
exit 1
fi
echo " In ogni progetto: ./start.sh (progetti con pannello) oppure bin/local-init.sh" echo " In ogni progetto: ./start.sh (progetti con pannello) oppure bin/local-init.sh"
echo " (Drupal e WordPress). Apri claude nella cartella del progetto: ti spiega il resto." echo " (Drupal e WordPress). Apri claude nella cartella del progetto: ti spiega il resto."
+22
View File
@@ -0,0 +1,22 @@
# Le chiavi dei tre server, lette sulle macchine stesse (/etc/ssh/ssh_host_*_key.pub)
# l'08/10/2026. configura.sh le scrive in ~/.ssh/known_hosts: senza, il primo
# collegamento chiede "Are you sure you want to continue connecting?" e
# verifica.sh, che non puo' rispondere, dice "non entri" anche a chi la chiave
# sul server ce l'ha. Se un server viene reinstallato, qui vanno quelle nuove.
#
# Il nome e' lo HostName di comune.sh, non il nome corto: e' quello che ssh cerca.
# oto-staging
10.110.185.10 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEdXcmBdVpVzOeRBU7qG22eKxeqrupuhc/vQhlz3hATP
10.110.185.10 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD6WAf8go/g6PPmAoNTbz53Khg/wFa3da6BPwnJj/bALJ0QBsmd0Dx7f446oQEia7CMGbAAKRjRdNgbSOaI3LNc=
10.110.185.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5j0lk5bMjFDBzqzsh20sF2C/h8kkmekxI/QxsZxSlWT1WFnHCNa3GC0umSQmPKjoZF639dZUDsbE/3UbrwJICD03arQGlClEu/i7ct6eWPhPT71vtH0BAUcjYKWK9dst5dAG4cd1mGP2hCtYTGMXo7KnzPprUTHVytf3KOcRydwlaRchFhxXnzPBVaaIAAvF7++ZNq0krRvw3X5G1tOPCSViiR1w7jmeX/UiDaS/4avJ4TXzqDQG56C1VG/iAxjeImJLQxQAkQMz+J6RG+g7kDGlSpiO8COFLyqgfgDjVV2ZUDqgZdrVb6HOwnIx2eqRCvsRA1G7HHuYp1tECZEkUToGx0P4D9ee38FwKXJ34cslOtz494ZCKF9vvd99602WKQxudNZxKv6/gXdVeBS2UjLVCYfCX+aSvOGJBCheC8sy4dDTeeO9keGV/KfIHRQy27Lgr7tswBabASjTHiOFZvbAeETWi9wtwb0Eyg3PYZ3KAnc+zNx5maqeLnJxQ+9M=
# oto-production
10.110.137.20 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAx5QWSl3YsMGEerqfYRhrXSy5PIdiHQW5rf/yiiLZhv
10.110.137.20 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBB41d5/XnLsNI4dYfx9IRnSOsFnazb6EvsLRKCotxSgXmrp7Ds+6cnoSB141+Tgj9xNA6NrfI3XuCfLQw1ZQYXw=
10.110.137.20 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb1sVTJkOoPfUQvZv2TNRNXr180OYO+Ua2yLeDFRpqxevgGiQz7amDcrW1M2ouokkI8YTDBc6bzMXLrWRRI34gTZHe9jYp9kEs+G+1XZnsd2fVoKY7Ix7dV33IRPb4qXb9KT4k9XgnygCRSrjhQNtjO6aFy0IfGWZF75jxDeRs3AWs0bllrJ1TMX91sCxlaYvUkehDqkavocpl4praiQDXnwdDFKiqGfQAFhcTLVfBetNIBx+T1Fvu/8FA24rogVcECkqdxO8PKpEA90rwQt0KwzIqHVcrbxP9vKlddX37spf4wSeJMo/T7w7iU5b1q5PKhxgWxHCRP9Hf09laYdDAiwZs1F9Sv6KWbVGKzhkQvVZF1nzWfPPo9UeyRDRpF5TORi0eeXUem2LprG/msJG1AJX7K0GN4QyuozzQqQr5NKFY7JjlxWS5Q+pZKCvJdaJU6Tvtc8oE8qtIerjdnCnz9eE3bfjPnMwmsPh8dSyGSK97g49Z/W8YWnug96CYCnU=
# oto-production-old
vps-production.oto-farm.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKjqHPAj0yN1PdWbIvJPAc1i/M2fGE6LH9W0ggNOqUda
vps-production.oto-farm.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKCfOvVGQPwctSwrTEPalC8fdhAawKVOlv/uIfIljZTCxX25+u7vw2+NlYhq7ETrSQvLAzaf3cOlbu2/qXUB3OA=
vps-production.oto-farm.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtikmWxIRAi73fvYXxyqji84qkSt3G2Psqe+ynnwe0iQ6bvf0elYU4HOIdta7MtJjAiRHeXkH7hvlAorXL9+nagzA+2AVs2YM0rF4mTQO6thpUOPh0U7kHAj7WAJMjogJBJ3wA9A1N1VMHdOPc1trK7OTGJ6BCFKVjglsaBh2n/v5Hl4wpTORTpXNbwpxBfr9TtXtqYb/csSURi2LZEewkLZFrWkKyhHWTmiSSHl8QEjgf+/hoafXeAJ7bxv0lZ2h5QGuyV6KN3A9lQ4omFE+2ug+pqQH31Xn934W5Bwt6QI/yjOjcwn4yMKr2wfQRk85qkIESovmH3I2g8ivY8cB3y358cBsz1LMQ2+NJlzbvVrqDAFLPAgBPNeU442bosvX92gIgXWRxhwHjoCc1/BaoyNidPw7aQ6teDb0HicwKfXAAaS9pamhMjdqz4uGiC0iiPbhrxUX/UOviTh8Oy4AniHFxSj3Afs1k5JBNUotXc2o2ZOsuj3Sy4XCUTZtj6LE=
+87 -29
View File
@@ -2,7 +2,8 @@
# #
# DICE VERDE O ROSSO PER OGNI ACCESSO, e per ogni rosso cosa fare. # DICE VERDE O ROSSO PER OGNI ACCESSO, e per ogni rosso cosa fare.
# #
# ./verifica.sh # ./verifica.sh # per chi ha la VPN
# ./verifica.sh --senza-vpn # per chi non la ha: staging non raggiungibile e' giallo
# #
# Non modifica niente e non chiede niente: si puo' lanciare quando si vuole, # Non modifica niente e non chiede niente: si puo' lanciare quando si vuole,
# anche da Claude. Esce 0 se e' tutto verde, 1 altrimenti. # anche da Claude. Esce 0 se e' tutto verde, 1 altrimenti.
@@ -11,6 +12,15 @@ set -u
cd "$(dirname "$0")" || exit 1 cd "$(dirname "$0")" || exit 1
. ./comune.sh . ./comune.sh
# Chi non ha la VPN non arriva a staging, ed e' giusto cosi': senza questa
# opzione quel rosso faceva uscire 1 anche un PC preparato bene per il suo ruolo.
SENZA_VPN=0
case "${1:-}" in
--senza-vpn) SENZA_VPN=1 ;;
"") ;;
*) echo "Uso: ./verifica.sh [--senza-vpn]" >&2 ; exit 2 ;;
esac
ROSSI=0 ROSSI=0
rosso () { male "$@" ; ROSSI=$((ROSSI + 1)) ; } rosso () { male "$@" ; ROSSI=$((ROSSI + 1)) ; }
@@ -24,17 +34,44 @@ if c_e docker ; then
fi fi
if c_e claude ; then ok "Claude Code" ; else attento "Claude Code non installato (non obbligatorio, ma ti guida)" ; fi if c_e claude ; then ok "Claude Code" ; else attento "Claude Code non installato (non obbligatorio, ma ti guida)" ; fi
titolo "Gitea"
UTENTE="$(utente_gitea)" ; ESITO_GITEA=$?
if [ -n "$UTENTE" ] ; then
ok "token valido (utente $UTENTE)"
# Si chiede a git la credenziale che userebbe davvero: un gestore qualsiasi
# configurato non vuol dire che abbia quella giusta, e un token vecchio
# rimasto li' fa funzionare l'API ma non git clone.
GIT_PASSWORD="$(password_git_gitea)"
if [ "$GIT_PASSWORD" = "$(token_gitea)" ] ; then
ok "git entra su $GITEA_HOST con il tuo token"
elif [ -n "$GIT_PASSWORD" ] ; then
rosso "git usa un accesso a Gitea diverso dal tuo token (vecchio o di un altro): rilancia ./configura.sh, che lo sostituisce"
else
rosso "git non ha le credenziali di Gitea: rilancia ./configura.sh"
fi
unset GIT_PASSWORD
elif [ "$ESITO_GITEA" = "2" ] ; then
rosso "Gitea ($GITEA_URL) non risponde: controlla la connessione a internet e rilancia"
else
rosso "token Gitea mancante o non valido: rilancia ./configura.sh"
fi
titolo "AWS" titolo "AWS"
# Chi e' la persona lo dice Gitea: una chiave AWS di un altro sul PC vuol dire # Chi e' la persona lo dice Gitea: una chiave AWS di un altro sul PC vuol dire
# che tutto quello che fa su AWS risulta fatto da lui. # che tutto quello che fa su AWS risulta fatto da lui. Senza Gitea non si puo'
UTENTE="$(utente_gitea)" # dire che la chiave sia sua, e quindi non e' verde.
if c_e aws && IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then AWS_OPZ=(--cli-connect-timeout 10 --cli-read-timeout 15)
if [ -n "$UTENTE" ] && [ "${IDENTITA##*/}" != "$UTENTE" ] ; then CONFLITTI="$(aws_variabili_in_conflitto)"
rosso "la chiave AWS di questo PC e' di ${IDENTITA##*/}, non tua ($UTENTE): rilancia ./configura.sh, che la sostituisce" [ -n "$CONFLITTI" ] && attento "nel terminale sono impostate $CONFLITTI: la AWS CLI usa quelle, non la chiave di ~/.aws/credentials"
if c_e aws && IDENTITA="$(AWS_MAX_ATTEMPTS=1 aws sts get-caller-identity "${AWS_OPZ[@]}" --query Arn --output text 2> /dev/null)" && [ -n "$IDENTITA" ] ; then
if [ -z "$UTENTE" ] ; then
rosso "c'e' una chiave AWS (${IDENTITA#arn:aws:iam::}), ma finche' Gitea non va non posso dire che sia tua"
elif aws_e_di "$IDENTITA" "$UTENTE" ; then
ok "accesso: $UTENTE"
else else
ok "accesso: ${IDENTITA##*/}" rosso "la chiave AWS di questo PC e' di ${IDENTITA#arn:aws:iam::}, non tua ($UTENTE nell'account OTO $AWS_ACCOUNT): rilancia ./configura.sh, che la sostituisce"
fi fi
if aws ssm get-parameter --region "$AWS_REGIONE" --name "$SSM_PROVA" --query Parameter.Name --output text > /dev/null 2>&1 ; then if AWS_MAX_ATTEMPTS=1 aws ssm get-parameter "${AWS_OPZ[@]}" --region "$AWS_REGIONE" --name "$SSM_PROVA" --query Parameter.Name --output text > /dev/null 2>&1 ; then
ok "legge i segreti comuni su SSM" ok "legge i segreti comuni su SSM"
else else
rosso "non legge SSM: all'amministratore serve darti il ruolo di sviluppo" rosso "non legge SSM: all'amministratore serve darti il ruolo di sviluppo"
@@ -43,20 +80,12 @@ else
rosso "AWS non configurato: rilancia ./configura.sh, che ti dice dove crearti la chiave nella console ($AWS_CONSOLE)" rosso "AWS non configurato: rilancia ./configura.sh, che ti dice dove crearti la chiave nella console ($AWS_CONSOLE)"
fi fi
titolo "Gitea"
if [ -n "$UTENTE" ] ; then
ok "token valido (utente $UTENTE)"
if grep -q "@$GITEA_HOST" "$HOME/.git-credentials" 2> /dev/null || [ -n "$(git config --global credential.helper)" ] ; then
ok "git sa come entrare su $GITEA_HOST"
else
rosso "git non ha le credenziali di Gitea: rilancia ./configura.sh"
fi
else
rosso "token Gitea mancante o non valido: rilancia ./configura.sh"
fi
titolo "Chiave SSH" titolo "Chiave SSH"
if [ -f "$CHIAVE_SSH" ] ; then ok "$CHIAVE_SSH" ; else rosso "chiave mancante: rilancia ./configura.sh" ; fi if [ -f "$CHIAVE_SSH" ] ; then ok "$CHIAVE_SSH" ; else rosso "chiave mancante: rilancia ./configura.sh" ; fi
# I nomi con cui la cercano i deploy dei progetti
for ALTRA in $CHIAVI_SSH_PROGETTI ; do
[ -e "$ALTRA" ] || rosso "manca $ALTRA, che usano i deploy dei progetti: rilancia ./configura.sh"
done
titolo "VPN e server" titolo "VPN e server"
# La VPN si riconosce da una cosa sola: staging, che sta su rete privata, # La VPN si riconosce da una cosa sola: staging, che sta su rete privata,
@@ -68,21 +97,50 @@ porta_aperta () {
kill "$sveglia" 2> /dev/null kill "$sveglia" 2> /dev/null
return "$esito" return "$esito"
} }
# Un tentativo, e il motivo se non si entra: "non entri" da solo faceva
# pensare ai ruoli anche quando mancava la chiave del server su questo PC.
# Esce 0 se si entra, 1 se e' la chiave tua, 2 se e' altro (scritto in MOTIVO).
entra () {
local errore
errore="$(ssh -o BatchMode=yes -o ConnectTimeout=8 "$1" true 2>&1 > /dev/null)" && return 0
case "$errore" in
*"Permission denied"*) return 1 ;;
*"Host key verification failed"*|*"IDENTIFICATION HAS CHANGED"*)
MOTIVO="questo PC non ha la chiave giusta del server: rilancia ./configura.sh, che la registra" ;;
*"Connection closed"*|*"Connection reset"*)
MOTIVO="il server ha chiuso la connessione: dopo troppi tentativi sbagliati la chiude per qualche minuto, aspetta e rilancia" ;;
*) MOTIVO="ssh dice: $(printf '%s\n' "$errore" | grep -v '^\*\*' | tail -1)" ;;
esac
return 2
}
if porta_aperta "$STAGING_HOST" 22 ; then if porta_aperta "$STAGING_HOST" 22 ; then
ok "VPN attiva (staging raggiungibile)" ok "staging raggiungibile (la VPN e' accesa)"
if ssh -o BatchMode=yes -o ConnectTimeout=8 "$STAGING_NOME" true 2> /dev/null ; then entra "$STAGING_NOME" ; ESITO=$?
ok "entri su staging ($STAGING_NOME)" if [ "$ESITO" = "0" ] ; then ok "entri su staging ($STAGING_NOME)"
else elif [ "$ESITO" = "1" ] ; then rosso "staging non accetta la tua chiave: l'amministratore deve ancora aggiungerla"
rosso "staging non accetta la tua chiave: l'amministratore deve ancora aggiungerla" else rosso "staging ($STAGING_NOME): $MOTIVO" ; fi
fi elif [ "$SENZA_VPN" = "1" ] ; then
attento "staging non raggiungibile: senza VPN e' normale"
else else
rosso "staging non raggiungibile: la VPN e' accesa?" rosso "staging non raggiungibile: la VPN e' accesa?"
fi fi
if ssh -o BatchMode=yes -o ConnectTimeout=8 "$PRODUZIONE_NOME" true 2> /dev/null ; then # Le produzioni sono due finche' i siti non sono migrati tutti. La nuova sta
ok "entri in produzione ($PRODUZIONE_NOME)" # dietro la stessa VPN di staging. Un tentativo solo per macchina: la nuova
# chiude le porte per un po' a chi sbaglia il login piu' volte di fila.
# Solo il rifiuto della chiave dipende dal ruolo: il resto si sistema da qui.
NON_AUTORIZZATO="il server non accetta la tua chiave (normale se non hai il ruolo di rilascio; se ce l'hai, chiedi a chi amministra di aggiungerla)"
if porta_aperta "$PRODUZIONE_HOST" 22 ; then
entra "$PRODUZIONE_NOME" ; ESITO=$?
if [ "$ESITO" = "0" ] ; then ok "entri in produzione ($PRODUZIONE_NOME)"
elif [ "$ESITO" = "1" ] ; then attento "produzione ($PRODUZIONE_NOME): $NON_AUTORIZZATO"
else rosso "produzione ($PRODUZIONE_NOME): $MOTIVO" ; fi
else else
attento "produzione: non entri (normale se non hai il ruolo di rilascio, o se la tua chiave non e' ancora stata aggiunta)" attento "produzione ($PRODUZIONE_NOME): non raggiungibile (sta dietro la VPN, come staging)"
fi fi
entra "$PRODUZIONE_VECCHIA_NOME" ; ESITO=$?
if [ "$ESITO" = "0" ] ; then ok "entri nella produzione vecchia ($PRODUZIONE_VECCHIA_NOME)"
elif [ "$ESITO" = "1" ] ; then attento "produzione vecchia ($PRODUZIONE_VECCHIA_NOME): $NON_AUTORIZZATO"
else rosso "produzione vecchia ($PRODUZIONE_VECCHIA_NOME): $MOTIVO" ; fi
titolo "Risultato" titolo "Risultato"
if [ "$ROSSI" = "0" ] ; then if [ "$ROSSI" = "0" ] ; then