Compare commits

..
17 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
7 changed files with 554 additions and 177 deletions
+90 -46
View File
@@ -3,11 +3,13 @@
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
la mail *I tuoi accessi OTO* che le ha mandato chi amministra (link, la mail *I tuoi accessi OTO* che le ha mandato chi amministra (link,
utenti, password, la frase per te) e, su LastPass, la chiave AWS e, se utente, email, la frase per te, **nessuna password**) e, su LastPass, due
sviluppa, la VPN. **Il lavoro 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
@@ -21,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
@@ -31,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
@@ -44,12 +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 di AWS e di Gitea | 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 | | 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 |
| 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 | | Password Gitea | su **LastPass**, scheda **`Gitea > nome.cognome`** (per esempio `Gitea > sara.locatelli`), campo *Password*. Nella mail non c'è, apposta |
| Chiave di accesso AWS (*Access key ID* e *Secret access key*) | in una **nota LastPass** condivisa da chi amministra (non nella mail, 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 | | 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*) | 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 |
| Utente Gitea | è nella mail (`nome.cognome`); su Gitea lo vede in alto a destra, cliccando l'icona del profilo | | Utente Gitea | è nella mail (`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 e credenziali della VPN | in una **nota LastPass** condivisa da chi amministra: il file `.ovpn` è allegato alla nota (*Attachments* → si scarica, finisce in *Download*), utente e password della VPN sono scritti nella nota. Il programma è **OpenVPN Connect**, lo installi tu. Se la nota non c'è, 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,74 +82,95 @@ 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
1. **Programmi.** Servono git, la AWS CLI, Docker, curl e ssh. Installa 1. **Programmi.** Servono git, la AWS CLI, Docker, curl e ssh. Installa
quello che manca: quello che manca:
- **Windows**: `winget install -e --id Git.Git`, `Amazon.AWSCLI`, - **Windows**: `winget install -e --id Git.Git`, `Amazon.AWSCLI`,
`Docker.DockerDesktop` e, per chi sviluppa, `Docker.DockerDesktop`. Docker vuole WSL2: `wsl --install`, poi un
`OpenVPNTechnologies.OpenVPNConnect`. Docker vuole WSL2: `wsl --install`, poi un
riavvio. Windows chiederà conferma (finestra *Sì/No*): avvisa prima che riavvio. Windows chiederà conferma (finestra *Sì/No*): avvisa prima che
arriva e che va cliccato *Sì*. Dopo un'installazione il `PATH` nuovo lo arriva e che va cliccato *Sì*. Dopo un'installazione il `PATH` nuovo lo
vede solo un terminale nuovo. vede solo un terminale nuovo.
- **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
(per chi sviluppa anche `brew install --cask openvpn-connect`). 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. **Il login su AWS nel browser**, lo fa lei. Le password della mail di 3. **Niente login su AWS né su Gitea nel browser** (deciso il 07/10/2026):
benvenuto sono già le definitive (dal 07/10/2026): né AWS né Gitea le password sono già le definitive e l'MFA di AWS lo attiva chi
chiedono di cambiarle, e su Gitea dal browser non c'è niente da fare. amministra, con il seme nella scheda LastPass `AWS > Nome Cognome`. La
- **AWS**: entrare dall'indirizzo della mail di benvenuto (*IAM user*, chiave di accesso **non** la crea: è già nel campo di testo di quella
utente e password) e attivare scheda. Solo se lì non c'è, la crea dalla console AWS (percorso nella
l'MFA. I percorsi esatti sono nella tabella qui sopra: dàglieli un passo tabella qui sopra), entrando con utente, password e codice a due fattori
alla volta. La chiave di accesso **non** la crea: è già nella nota della stessa scheda.
LastPass. Se lì non c'è, la crea adesso, e lascia aperta la pagina: la
parte segreta si vede una volta sola.
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, che lei copia dal password di Gitea (l'utente dalla mail, la password dalla scheda
la nota LastPass; crea l'accesso a `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`. Gitea viene prima apposta: è lui a dire chi è la persona. Se sul PC scrive i nomi dei server in `~/.ssh/config` e le loro chiavi in
`~/.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). OpenVPN Connect l'hai già installato tu; lei, 5. **VPN**, solo se su LastPass ha la scheda `OTO > VPN HK nome.cognome` (chiediglielo). Prima
un passo alla volta: apre la nota VPN su LastPass e scarica il file va installato OpenVPN Connect: su Windows lo installi tu,
`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 `.ovpn` allegato; apre OpenVPN Connect → *Upload File* (o *Import
Profile* → *File*) → *Browse* → il file in *Download*; scrive utente e Profile* → *File*) → *Browse* → il file in *Download*; scrive utente e
password della VPN dalla stessa nota, spunta *Save password*, *Connect*. password della VPN dalla stessa scheda, spunta *Save password*, *Connect*.
È accesa quando l'interruttore diventa verde (*Connected*). È accesa quando l'interruttore diventa verde (*Connected*).
6. **Dirlo all'amministratore**: risponde alla mail *I tuoi accessi OTO* 6. **Dirlo all'amministratore**: risponde alla mail *I tuoi accessi OTO*
scrivendo «ho finito la configurazione». È il segnale 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.
@@ -150,4 +188,10 @@ Dillo alla persona, invece di farle scoprire un rosso inspiegabile:
`~/.ssh/config` ci sono `oto-production` (la macchina nuova, dietro la VPN `~/.ssh/config` ci sono `oto-production` (la macchina nuova, dietro la VPN
come staging, utente `admin.produzione`) e `oto-production-old` (quella 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 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. 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`.
+7 -5
View File
@@ -12,10 +12,12 @@ scaricano i progetti stessi da AWS, con il tuo accesso personale.
> Scarica il progetto https://git.oto-farm.com/admin/_OTO_IT_onboard e prepara il mio PC per OTO > 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.
Utenti e password sono nella mail *I tuoi accessi OTO* che ti ha mandato chi L'utente e' nella mail *I tuoi accessi OTO* che ti ha mandato chi amministra;
amministra; la chiave AWS e la VPN in una nota LastPass condivisa con te. 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
@@ -31,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
+69 -8
View File
@@ -6,13 +6,17 @@
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 e la # I server, con i nomi che usano gli script dei progetti. Staging e la
# produzione nuova stanno su rete privata: senza VPN non rispondono. Le # produzione nuova stanno su rete privata: senza VPN non rispondono. Le
@@ -46,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'
} }
+195 -58
View File
@@ -1,6 +1,6 @@
#!/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
# #
@@ -8,27 +8,57 @@
# 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.
# La password e' quella della mail di benvenuto: dal 07/10/2026 Gitea non # La password e' nella scheda LastPass "Gitea > nome.cognome", condivisa da
# 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 # obbliga piu' a cambiarla. Chi e' stato creato prima invece deve ancora
# cambiarla nel browser, e Gitea gli risponde 403: lo si dice sotto. # cambiarla nel browser, e Gitea gli risponde 403: lo si dice sotto.
UTENTE="$(utente_gitea)" 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 di Gitea sono nella mail \"I tuoi accessi OTO\" che ti ha" echo " L'utente Gitea e' nella mail \"I tuoi accessi OTO\" che ti ha mandato chi"
echo " mandato chi amministra: copiali da li'." echo " amministra. La password no: e' su LastPass, nella scheda \"Gitea > nome.cognome\""
echo " col tuo utente (per esempio \"Gitea > sara.locatelli\"), campo Password."
read -r -p " Il tuo utente Gitea (dalla mail, riga utente Gitea): " UTENTE_DATO read -r -p " Il tuo utente Gitea (dalla mail, riga utente Gitea): " UTENTE_DATO
read -r -s -p " La tua password Gitea, dalla nota LastPass (non si vede, ed e' normale): " PASSWORD ; echo read -r -s -p " La tua password Gitea, dalla scheda LastPass \"Gitea > $UTENTE_DATO\" (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,48 +66,70 @@ 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)"
ok "accesso Gitea salvato in $TOKEN_GITEA_FILE (utente $UTENTE)" if [ -n "$UTENTE" ] ; then
ok "accesso Gitea salvato in $TOKEN_GITEA_FILE (utente $UTENTE)"
else
errore "Gitea ha creato l'accesso ma non lo riconosce: rilancia, e se si ripete avvisa l'amministratore."
fi
elif [ "$CODICE" = "403" ] ; then elif [ "$CODICE" = "403" ] ; then
male "Gitea chiede prima di cambiare la password: entra su $GITEA_URL (Sign in), scegline una nuova, salvala su LastPass e rilancia." 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 elif [ "$CODICE" = "401" ] ; then
male "utente o password sbagliati: rilancia e riprova." errore "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 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
[ -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)>)"
else
errore "git non riesce a ricordare l'accesso a Gitea: avvisa l'amministratore, con il messaggio qui sopra."
fi fi
ok "git configurato ($(git config --global user.name) <$(git config --global user.email)>)"
fi fi
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
titolo "2. AWS" titolo "2. AWS"
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# La chiave di accesso la crea chi amministra insieme all'utente, e la # La chiave di accesso la crea chi amministra insieme all'utente, e la
# persona la trova nella nota LastPass della chiave AWS: qui la si incolla # persona la trova su LastPass, nel campo di testo della scheda
# "AWS > Nome Cognome": qui la si incolla
# una volta e finisce in ~/.aws/credentials, dove la leggono la AWS CLI e gli # 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 # 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. # ne crea una dalla console: la strada e' scritta qui sotto.
@@ -85,13 +137,26 @@ titolo "2. AWS"
# 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: Access key ID e Secret access key." echo " Serve la tua chiave di accesso AWS, due pezzi: Access key ID e Secret access key."
echo " Non sono nella mail: li trovi nella nota LastPass che ti ha condiviso" # Il nome della scheda e' quello per esteso: sara.locatelli -> Sara Locatelli.
echo " chi amministra. Se li' non c'e', la crei tu nella console AWS:" 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 " 1. entra su $AWS_CONSOLE (IAM user, utente e password" echo " Non sono nella mail: li trovi su LastPass, nella scheda \"$SCHEDA_AWS\" che ti"
echo " della mail di benvenuto);" 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."
@@ -104,35 +169,63 @@ 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
errore "AWS non accetta questa chiave: controlla di aver copiato i due pezzi interi, senza scambiarli, e rilancia. Non l'ho salvata."
return 1
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 unset CHIAVE_SEGRETA
if ! IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then [ -f "$HOME/.aws/credentials" ] && chmod 600 "$HOME/.aws/credentials"
male "AWS non accetta questa chiave: controlla di aver copiato i due pezzi interi, senza scambiarli, e rilancia." if [ "$esito" != "0" ] ; then
elif [ -n "$UTENTE" ] && [ "${IDENTITA##*/}" != "$UTENTE" ] ; then errore "non riesco a salvare la chiave in ~/.aws/credentials: avvisa l'amministratore, con il messaggio qui sopra."
male "questa chiave e' di ${IDENTITA##*/}, non tua ($UTENTE): usa quella della tua nota LastPass, e rilancia." return 1
else
ok "accesso AWS: ${IDENTITA##*/}"
fi 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
CONFLITTI="$(aws_variabili_in_conflitto)"
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 " dal PC del suo proprietario e va disattivata."
chiedi_chiave_aws
fi
else else
attento "su questo PC c'e' gia' una chiave AWS, ma e' di ${IDENTITA##*/}, non tua ($UTENTE)."
echo " Usandola, tutto quello che fai su AWS risulterebbe fatto da ${IDENTITA##*/}."
echo " La sostituisco con la tua. Avvisa l'amministratore: quella chiave e' uscita"
echo " dal PC di ${IDENTITA##*/} e va disattivata."
chiedi_chiave_aws chiedi_chiave_aws
fi fi
else
chiedi_chiave_aws
fi fi
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
@@ -143,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
@@ -176,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 <<<"
@@ -204,11 +310,42 @@ Host $1
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, ssh $PRODUZIONE_NOME e ssh $PRODUZIONE_VECCHIA_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: accendi la VPN (file e credenziali nella nota LastPass), poi torna da Claude." 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=
+82 -36
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,33 +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
# Le produzioni sono due finche' i siti non sono migrati tutti. La nuova sta # Le produzioni sono due finche' i siti non sono migrati tutti. La nuova sta
# dietro la stessa VPN di staging. Un tentativo solo per macchina: la nuova # 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. # 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 if porta_aperta "$PRODUZIONE_HOST" 22 ; then
if ssh -o BatchMode=yes -o ConnectTimeout=8 "$PRODUZIONE_NOME" true 2> /dev/null ; then entra "$PRODUZIONE_NOME" ; ESITO=$?
ok "entri in produzione ($PRODUZIONE_NOME)" if [ "$ESITO" = "0" ] ; then ok "entri in produzione ($PRODUZIONE_NOME)"
else elif [ "$ESITO" = "1" ] ; then attento "produzione ($PRODUZIONE_NOME): $NON_AUTORIZZATO"
attento "produzione ($PRODUZIONE_NOME): non entri (normale se non hai il ruolo di rilascio, o se la tua chiave non e' ancora stata aggiunta)" else rosso "produzione ($PRODUZIONE_NOME): $MOTIVO" ; fi
fi
else else
attento "produzione ($PRODUZIONE_NOME): non raggiungibile (sta dietro la VPN, come staging)" attento "produzione ($PRODUZIONE_NOME): non raggiungibile (sta dietro la VPN, come staging)"
fi fi
if ssh -o BatchMode=yes -o ConnectTimeout=8 "$PRODUZIONE_VECCHIA_NOME" true 2> /dev/null ; then entra "$PRODUZIONE_VECCHIA_NOME" ; ESITO=$?
ok "entri nella produzione vecchia ($PRODUZIONE_VECCHIA_NOME)" if [ "$ESITO" = "0" ] ; then ok "entri nella produzione vecchia ($PRODUZIONE_VECCHIA_NOME)"
else elif [ "$ESITO" = "1" ] ; then attento "produzione vecchia ($PRODUZIONE_VECCHIA_NOME): $NON_AUTORIZZATO"
attento "produzione vecchia ($PRODUZIONE_VECCHIA_NOME): non entri (normale se non hai il ruolo di rilascio, o se la tua chiave non e' ancora stata aggiunta)" else rosso "produzione vecchia ($PRODUZIONE_VECCHIA_NOME): $MOTIVO" ; fi
fi
titolo "Risultato" titolo "Risultato"
if [ "$ROSSI" = "0" ] ; then if [ "$ROSSI" = "0" ] ; then